前言
线程间通讯主要是经过wait、notify来实现的,使用这种机制实现线程通讯是很是效率的,相比而言,不知道的同窗针对线程通讯可能只会想到轮询的方式,下次可别再去轮询共享变量了,把线程协做机制用起来。编程
1、线程协做的要素
首先,若是了解显式锁ReentrantLock或显式条件Condition,咱们就会知道锁的队列不止有一个等待队列,还有一个等待条件队列,存放等待被唤醒的线程。 对于用声明式编程synchronized关键字来讲,底层也是这种原理,对应的针对等待条件队列入队出队方法就是锁资源的wait/notify/notifyAll方法。但光有这种机制只能表示咱们线程能够触发其余线程继续执行,前面说了叫等待条件队列,那条件究竟是什么勒?通常来讲条件就是线程间共享的一个变量,这个变量用于控制线程等待或继续执行。总结来讲,notify通常伴随着一个条件共享变量的改变,wait通常伴随着一个条件共享变量的不知足。好比以下代码:并发
synchronized (this) {
while (!condition) {
wait();
}
}
最开始condition不知足,该线程放弃CPU执行权,进入等待条件队列,而后等到其余线程作了其余过后,条件共享变量被改变,而后该线程被唤醒,而后继续执行。异步
2、线程协做的场景
线程间的基本协做机制大体分为如下几种:this
- 生产者/消费者协做模式,生产者线程和消费者线程共享一个队列变量,为了控制队列的长度上限,当队列为满时,限制生产者线程等待,当添加信息到队列时,队列不为空,唤醒消费者队列,当队列为空时限制消费者线程等待,取到信息时,队列不为满,唤醒生产者队列。
- 同时开始,全部子线程根据一个共享变量等待一个条件,同时开始的意思是主线程改变这个共享变量同时移除全部在等待条件队列中的线程,如模拟仿真程序中,要求多个线程能同时开始。
- 等待结束,thread.join()方法的底层原理是while(子线程未结束){wait(0)},等待子线程结束。更好的方式实现是经过Java的CountDownLatch类来控制主线程的等待,子线程每结束一个线程计数器减1,主线程的等待条件是计数器为0,使用线程计数器也能够实现同时开始,只须要让子线程共享线程计数器变量,等待条件是线程计数器为0,主线程将一个线程计数器传入多个子线程并运行子线程,在一个时刻将线程计数器countDown为0就好了。这个主要是应用在主从协做模式中,主线程将任务分解为若干个子任务,为每一个子任务建立一个线程,主线程在继续执行其余任务以前须要等待每一个子任务执行完毕。
- 异步结果,jdk并发包对异步任务进行了封装,主要用于主从协做场景,若是不想手工建立线程,管理线程可使用Excutors异步任务执行服务,核心是Future接口的get方法,该方法将等待异步任务返回执行结果,而后才会被唤醒并返回结果。
- 集合点,并发包中的CyclicBarrier栅栏就是这种场景的应用,一组子线程同时等待全部其余线程到一个地方以后再开始执行下面的逻辑,如一些并行计算场景,每一个线程负责一部分计算,而后在集合点等待其余线程完成,全部线程到齐后,交换数据和计算结果,再进行下一次计算。