jdk1.5后,提供了Condition接口,主要常用的实现类是AQS里的ConditionObject;常用的方法await(),single()刚好对应Object类的wait(),notify();区别在于前者能指定唤醒阻塞的线程,看ArrayBlockedList源码可以看到,其阻塞的实现就是利用Condition实现的。下面开始研究下源码的实现。
首先看常见的用法
上面代码模拟了两个线程的同步的过程,首先condtion.await()和single()必须是在加锁范围内执行的,通过上面的执行步骤,可以清晰的理解线程之间是如何阻塞和唤醒的。
下面就按上述的场景流程,看下await()和single()过程中做了什么。
之前还得先了解下ConditonObject的结构,Node就是AQS里的节点,可以看到它自己有一个队列,和AQS的线程队列不是同一个。
1.thread1.lock()
thread1获取锁
2.thread2.lock()
thread2获取锁失败,进入线程队列并阻塞,最后AQS的线程队列为
3.conditon1.await()
3.1 addConditionWaiter
新建了一个Node,(Node.CONDITION=-2),firstWaiter和lasterWaiter都指向它,注意这里的队列和之前的线程队列不是同一个队列。
3.2fullyRelease
3.3 release
调用release方法,thread1释放锁
3.4 unparkSuccessor
最后将thread2阻塞唤醒
3.6 isOnSyncQueue
返回false,下一步park理解为阻塞在当前位置,唤醒后也从这里继续往下执行。
这次thread2被唤醒继续执行,thread1被阻塞。此时AQS线程队列
4.thread2.lock()上一步唤醒阻塞,这里继续往下执行,thread2获取到锁
5.condition1.single()
5.1 isHeldExclusively()
是否占有排它锁,返回ture
5.2 doSignal
firstWaiter和lastWaiter都为null
5.3 transferForSignal
最后唤醒thread1,等thread2执行完unlock()释放锁后,thread1继续执行。
大体通过代码自己分析了一遍过程,里面还有很多细节需要深究
标签:队列,阻塞,线程,thread2,thread1,唤醒,Condition From: https://www.cnblogs.com/zeenzhou/p/17602587.html