Java精通并发-通过Condition实现线程间通信实例剖析【上】
了解实例的实现细节:
在上一次https://www.cnblogs.com/webor2006/p/11906700.html咱们对Condition这个类的方法进行了大致的解读,接下来则会通过一个非常完整的例子来加深对Condition类的使用,在正式撸码之前,先回忆一下在之前https://www.cnblogs.com/webor2006/p/11423023.html我们利用synchronized实现过对一个整数的+-操作,当时实现的是这样的一个功能:
其实就是生产消费者,这次举的例子其实跟它也类似,不过条件要比它复杂一些,例子的前身其实是Condition中的javadoc上提及的,回忆一下:
不过官方的这个代码示例不全,这里以它为蓝本来进行撸码,下面先明白这个示例要完成的功能是啥?
从官方的类名就可以得知这是一个“有界的缓冲”,里面是用数据来实现的,下面用图来表示一下最终程序的一个效果:
然后里面存在2个方法,一个方法是往这个数组中添加元素,一个是往数组里读取元素,也是生产与消费:
好,接下来先生产:
然后开始消费,消费完了需要将当前元素置空,以便之后该位置可以继续被生产,而默认消费的位置是从头开始,所以先来消费一个,形态变为:
接下来继续来消费,所以:
好,接下来则轮到生产数据了,此时注意了,生产是会延着上一次生产的位置继续生产,而非是从头开始找null的地方来生产,比如又生产了2个数据,就会变成这样了:
接着又轮到消费线程来执行了,这时也类似,是会延着上一次消费的位置继续消费,比如消费了一次情况就会变成这样了:
所以根据上面的过程来看很显然是需要有变量来记住生产与消费的上一次的位置的,好,继续来分析流程,假如说又来了一个生产线程了,目前的数组的最后一个位置已经有数据了:
此时就会从头来查找为null的位置,然后再数据再按之前的规则进行存放,假如连续生产3个数据,形态就如:
此时再来一个生产线程,很明显目前数组中没有为null的位置了,也就是数据已经满了,所以这个生产线程则会进行等待,等待着消费者进行消费,比如这时有一个消费者进行了一次消费,注意消费的位置还是延着上一次的位置往下进行:
好,此时会通知正在等待其中的一个消费者进行消费,所以当消费者拿到锁之后,则会在刚才消费的位置进行生产,如下:
类似的,假如当所有的元素都消费掉了,也就是这样一个形态:
那此时消费者线程则会等待,等待有生产者生产了数据之后再进行消费。
以上则为例子要完美的功能,说实话还是比较麻烦的,各种条件,但是把这个例子用Condition实现了之后,对它的使用也会了解得更加深刻,好下面则正式开始实现。
具体实现:
先来定义相关的一些成员变量:
然后对于同一个数组的操作(取或存)肯定也需要进行同步处理,同一时间只能有一个动作执行,这里咱们不用传统的synchronized了,而是采用咱们现在学习的Lock,所以先定义一下:
另外需要两个Condition,应对当数组不为空和数组不满时的条件,其实也就是需要调用它的await()方法进行逻辑控制的,所以:
记住:一个lock可以生成多个Condition对像,接下来还有一些其它的变量需要提前定义,一个是数组中已有的元素的数量,用来判断数组是否满了,如下:
另外,从图解中可以发现需要再定义两个变量,用来记录从哪读,从哪写,所以定义如下:
好,暂且这次先把要用到的成员变量给定义好了,正式的逻辑编写放到下次再来学习。