小记
好久没更博,窗外光芒万丈,冬日的晚晨,多么美好,就不浪费了,循着键盘上的点点星辰,开工!
啥子是条件队列?
我们都知道,在万类之祖Object里面定义了几个监视器方法:wait(),notify
(),notifyAll(),配合synchronized语义来控制线程的一些状态,在JDK1.5之后,由Lock替代了synchronized,而这几个监视器由条件队列Condition来实现,以便在某个状态条件现在可能为 true 的另一个线程通知它之前,一直挂起该线程(即让其“等待”),以原子的方式释放锁,并挂起当前线程,所以,也可以叫它为线程的条件队列
(自创的)。
来看一个应用示例
在以前刚学习Java的时候写过一个题,题干大概是这样的:开启三个线程依次轮流打印出75个数,且次序不能乱。下面是代码:
1 | 复制代码import java.util.concurrent.locks.Condition; |
抛开当时混乱的逻辑和性能考虑不足不谈,这段丑陋的代码,终归是实现了功能,而且是运用了Lock和Condition来实现的,用在这里来说明Condition的语义再好不过了。代码中初始化了3个条件队列,分别来控制3个线程的挂起状态,flag变量则控制它们之间的关系。
与Lock之间的实现关系
Condition是一个接口,其实现类只有两个:AQS和AQLS,都以内部类的形式存在,内部类叫做ConditionObject,这里有点纳闷,既然这个类是为Lock专属定制的,为什么不在ReentrantLock里面来实现呢?放在AQS不会太臃肿吗?不知道Doug Lea上神当时是怎么考虑的。 由于在AQS中已经实现,因此在ReentrantLock里面对其操作也是很简单的,创建一个条件队列:
1 | 复制代码 public Condition newCondition() { |
sync中的实现:
1 | 复制代码 abstract static class Sync extends AbstractQueuedSynchronizer { |
很简单吧?呵呵,下面来看ConditionObject
ConditionObject实现
首先定义了两个核心成员变量,条件队列的头节点和尾节点:
1 | 复制代码/** First node of condition queue. */ |
1、核心方法:await() 不可中断的条件等待实现
1 | 复制代码public final void await() throws InterruptedException { |
简而言之,await()方法其实就是为当前线程创建一个Node节点,加入到Condition队列并释放锁,之后就一直查看这个节点是否在Sync队列中了(signal()方法将它移到Sync队列),如果在的话就唤醒此线程,重新获取锁。此外,awaitNanos(long nanosTimeout) 方法和await(long time, TimeUnit unit) 方法的实现大同小异,只是在何时跳出while循环的时候加了一个超时罢了。 另外还有几个相关的方法也看一下:
1 | 复制代码/** |
1 | 复制代码 /** |
1 | 复制代码 /** |
2、核心方法:signal() 将等待时间最长的线程(如果存在)从Condition队列中移动到拥有锁的Sync队列
1 | 复制代码 public final void signal() { |
1 | 复制代码 private void doSignal(Node first) { |
1 | 复制代码 final boolean transferForSignal(Node node) { |
3、核心方法:signalAll() 将所有线程从Condition队列移动到拥有锁的Sync队列中。
1 | 复制代码 public final void signalAll() { |
1 | 复制代码 /** |
本文转载自: 掘金