
深入理解Condition
前言
建议先看一下这篇分享,深入理解AbstractQueuedSynchronizer,这篇文章主要介绍了AQS的同步队列实现,而本篇文章主要介绍AQS条件队列的实现
在进行线程间的通信时,当我们使用synchronized时,可以用基于Object对象的wait和notify方法实现等待/通知机制,但是在AQS相关类中怎么实现这种等待/通知机制呢?答案是Condition,Condition是一个接,AbstractQueuedSynchronizer中有一个内部类实现了这个接口
基于Object实现等待/通知机制的相关方法
举个例子
这里有几个需要注意的点
- 第三行和第四行的顺序有可能颠倒,因为是竞争获取锁的
- wait()方法被执行后,锁被自动释放,但notify()方法被执行后,锁却不自动释放 ,必须执行完notify()方法所在的同步synchronized代码块后才释放锁
基于Condition实现等待/通知机制(包含了Condition接口的所有方法)
Conditon使用例子如下,可以实现条件性的通知
WaitThreadB因为没有被通知,一直阻塞 ,这里说一下Condition的大概实现,AQS内部维护着一个同步队列(双向链表实现),多个条件队列(单向链表实现),条件队列由AQS的内部类ConditionObject来维护,new一个ConditonObject ,则多一个条件队列,当一个线程执行await方法是,会把当线程包装成一个Node节点,放到执行await方法的ConditionObject的条件队列中,释放锁并被阻塞,当执行signal方式时,会把条件队列的第一个节点移除,并转移到同步队列中,获取到锁即可继续执行
源码
基于jdk1.8.0_20 ,Object的监视器方法和Condition接口的对比
ConditionObject 是AQS的一个内部类,用来实现条件队列,属性如下
假如在阻塞过程中发生了中断,REINTERRUPT标志了中断发生在 signalled之后,THROW_IE标志了中断发生在 signalled之前,从而决定采用那种方式响应中断
来看await方法
将当前线程包装成Node节点,并放入等待队列
释放锁
判断节点是否在同步队列
检测线程在等待期间是否发生中断
清除条件队列中取消状态的节点
响应中断的方式
来看signal,唤醒等待时间最长的线程
signalAll和signal实现类似,区别如下,signal将等待队列中的一个非CANCELLED节点放到同步队列,而signalAll是将等待队列中的所有非CANCELLED节点放到同步队列中
参考书籍
《Java并发编程的艺术》
文章转载自公众号:Java识堂
