多线程

Dean0731 28天前 ⋅ 41 阅读

1,线程基础

1,继承Thread方式的线程

  • 当需要再此启动一个线程时,需要再创建对象,不能重复使用。

2,推荐的创建线程方式:继承Runnalbe,使用Thread类

  • 1.5之前就这两种

  • callable 第三种

    • 可以有返回值 call()

    • 可以抛出异常

    • 支持泛型返回值

    • 需要借助FutureTask, 如获取返回值的时候

    • class MyThread implements Callable{
          public Object call() throws Exception{
              ....
              return null;
          }
      }
      
      MyThread thread = new MyThread();
      FutureTask f = new FutureTask(thread);
      new Thread(f).start();
      new Thread(f).start(); // 反复执行不会执行,需要定义新的task
      try{
          Object ret = f.get();// get()为返回值,会阻塞主线程执行
      }catch(InterruptedException){
      
      }catch(Execution e){
      
      }
      

      image-20200906142542954

  • 线程池 第四种方式

    • 提高速度,降低资源消耗
    • 便于线程管理:核心池大小,最大线程数,没任务多长时间终止
    //Executors 工具类
    //ExecutorService 接口
    ExecutorService service = Executors.newFixedThreadPool(10);
    ThreadPoolExecutor executor = (ThreadPoolExecutor)service;
    executor.setxxx() //设置参数
    service.execute(Runnable);
    service.submit(Callable);
    service.shutdown();
    

3,Thread常用方法

getPriority()setPrioority(1,5,10)
currentThread() 静态方法getName()setName()
yield() 释放cup执行权,变为就绪状态join():在A线程中B.join() ,A就阻塞,B执行完到A
stop() :过时方法,强制结束线程sleep(ms)isAlive()

4,线程分类

守护线程,用户线程

守护线程服务用户线程

thread.setDaemon(true) //设置为守护线程
  • 最简单程序main主线程与gc回收线程
  • 若没有用户线程jvm则结束

5,线程生命周期

  • NEW : 创建对象
  • RUNNABLE :运行 start
  • BLOCKED:阻塞 sleep,join,等待同步锁,wait,suspend:过时方法
  • WAITING:wait()
  • TIMED-WAITING:wait(time)
  • TERMINATED:stop,exception,run结束

阻塞---》就绪:sleep,join结束获取同步锁,notify,resume:过时方法

6,注意

  • wait:阻塞,会释放锁,必须在synchronized内
  • sleep:阻塞,不会释放锁,任何时候可以

wait,notify,notifyall,必须在同步方法快内,方法内,不能使用lock,他们调用时是锁对象.wait,要注意 此时syn(锁对象),两个所对象必须相同

2,线程同步

  • sync

    • 与wait搭配,notify搭配,若与Lock搭配会造成异常

    • 多用while,不用if

    • 同步代码块,synchronized 自动锁

    • 要求所有相乘同一把锁 synchronized(obj) obj是同一个对象,或同一个类

    • 同步方法:当方法内容全部需要同步时

    • 非静态方法锁即时this 需要注意

    • 静态方法时,锁时当前类本身

  • Lock :接口 1.5之后

    • condition

    • 能够手动开启同步,结束同步,手动锁,指定睡眠,指定唤醒

    • 实现类

      • ReentrantLock:功能与synchronized,可重入锁
      • ReentrantReadWriteLock.ReadLock,有读锁的线程可以共享该方法,几乎相当于没加锁
      • ReentrantReadWriteLock.WriteLock,其他线程不共享该方法
    • ReentrantLock lock = new ReentrantLock();
      final Condition flag1=lock.newCondition();
      final Condition flag2=lock.newCondition();
      try{
         lock.lock();
          flag1.await();
             ...
      }finally{
          lock.unlock();
      }
      flag2.singal();
      

3,线程通信

定制化通信:

/* 例:
* 切菜
* 炒菜
* 上菜
* 同时10道菜
*/
// 这里就不能用sync,需要定制化通信(唤醒睡眠的线程)
// 顺序:线程 操作 资源类
Cooking
    Lock
    condation flag1,flag2,flag3
    cut()
    cooking()
    gaving()
Cooking
    new thread(()->{
        for(int i=0;i<5;i++)
            cooking.cut();
    }).start()
    new thread(()->{
        for(int i=0;i<5;i++)
            cooking.cooking();
    }).start()
    new thread(()->{
        for(int i=0;i<5;i++)
            cooking.giving();
    }).start()

  • lambda表达式
  • 接口可写静态方法实现,
  • 普通方法实现,加default 关键字即可

4,JUC工具类

数据库中读写一般不是同步的

JUC中读写都是同步的,即读写同步,因为JVM线程必须加锁,否则不安全,比数据库严格

  • ReentraReadWriteLock:读写锁,写程序优先

  • CountDownLatch:计数器

    CountDown count = new CountDown(10);
    count.await();  // 到此方法时会判断count里面的数值,为0时继续主线程,适用于秒杀业务
    
  • CyclicBarrier:循环栅栏,多个线程处于同一状态时,才继续CyclicBarrier任务

    CyclicBarrier = cyc = new CyclicBarrier(7,任务)
        for (int i=0;i<7;i++)
            new Thread(){
            ()->{
                xxxxx
                cyc.await();    
            }
        }
    
  • Semaphere:信号灯

    Sempahere s= new Semaphere(3);
        for (int i=0;i<7;i++)
            new Thread(){
            ()->{
                s.acquire();// 资源不够时会阻塞
                xxxx
                s.release();// 表示释放了资源
    
            }
        }
    

全部评论: 0

    我有话说: