1.开发中不免会遇到需要所有子线程执行完毕通知主线程处理某些逻辑的场景
2.或者是线程 A 在执行到某个条件通知线程 B 执行某个操作
3.多线程通讯机制,主要有三种机制
<1>传统线程通信synchronized + wait + notify
1.Object类的wait()、notify() 、notifyAll()三个方法必须由同步监视器对象来调用,分两种情况:
a)同步方法,该类默认实例(this)就是同步监视器,可以在同步方法中可以直接调用
b)同步代码块,同步监视器是synchronized后括号里的对象,所以必须使用此对象调用这三个方法
<2>使用Condition控制线程通信lock + condition + await + signal
1.Lock代替同步方法或同步代码块,Condition替代同步监视器的功能
a)// 构造一把锁
Lock lock = new ReentrantLock();
b)// 由锁创建一个条件阻塞Condition对象
Condition condition = lock.newCondition();
c)// 非住线程执行时,则等待
condition.await();
d)// 同时需要唤醒等待的线程(由condition给一个信号)
condition.signal();
e)// 释放锁对象
lock.unlock();
<3>使用阻塞队列(BlockingQueue)控制线程通信
1.主要作为线程同步的工具
2.当生产者试图向BlockingQueue中放入元素,如果队列已满,则线程被阻塞
3.当消费者试图向BlockingQueue中取出元素时,若该队列已空,则线程被阻塞
<4>线程池 awaitTermination() 方法
1.如果是用线程池来管理线程,可以使用以下方式来让主线程等待线程池中所有任务执行完毕:
private static void executorService() throws Exception{
BlockingQueue<Runnable> queue = new LinkedBlockingQueue<>(10) ;
ThreadPoolExecutor poolExecutor = new ThreadPoolExecutor(5,5,1, TimeUnit.MILLISECONDS,queue) ;
poolExecutor.execute(new Runnable() {
@Override
public void run() {
LOGGER.info("running");
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
poolExecutor.execute(new Runnable() {
@Override
public void run() {
LOGGER.info("running2");
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
poolExecutor.shutdown();
while (!poolExecutor.awaitTermination(1,TimeUnit.SECONDS)){
LOGGER.info("线程还在执行。。。");
}
LOGGER.info("main over");
}
a)使用这个 awaitTermination() 方法的前提需要关闭线程池,如调用了 shutdown() 方法
b)调用了 shutdown() 之后线程池会停止接受新任务,并且会平滑的关闭线程池中现有的任务
4.传统线程通信与使用Condition控制线程通信区别:
(1) 在Condition中,用await()替换wait(),用signal()替换notify(),用signalAll()替换notifyAll()
(2)传统线程的通信方式,Condition都可以实现
(3) Condition实例实质上被绑定到一个锁上,要为特定Lock实例获得Condition 实例,请使用其newCondition() 方法
(4)本质:Condition和传统的线程通信没什么区别
(5)Condition的强大之处在于它可以为多个线程间建立不同的Condition,这样可以控制多个线程之间的运行顺序
例如:子线程1循环10次,子线程2循环5次,接着主线程循环10次,然后又回到子线程1循环10次,子线程2循环5次,
再回到主线程又循环10次,如此循环50次