基本介绍
勾勾在学习多线程基础知识的时候,学习了Object的wait和notify方法,这对组合可以使线程进入阻塞并由其他线程唤醒,但是notify的唤醒不能明确线程。在实际的工作中,各个业务之间有明确的等待关系,那么在唤醒的时候就需要唤醒特定的线程。
AQS同步器提供了条件等待的实现类Condition,在Condition对象中与wait、notify、notifyAll对应的方法是await、signal、signalAll。今天的文章我们依然撇开Condition本身的实现原理先了解AQS底层的条件等待的实现机制。
AQS维护了内部类ConditionObject,其实现了Condition接口。源码关键信息如下:
public class ConditionObject implements Condition, java.io.Serializable {
private static final long serialVersionUID = 1173984872572414699L;
/** 条件等待队列中的第一个节点 */
private transient Node firstWaiter;
/** 条件等待队列中的最后一个节点*/
private transient Node lastWaiter;
/**
* 无参构造
*/
public ConditionObject() { }
/** 在退出wait方法的时候重新打断线程 */
private static final int REINTERRUPT = 1;
/**退出await方法的时候抛出异常*/
private static final int THROW_IE = -1;
...
}
条件等待.获取操作
ConditionObject类重写了Condition定义的await方法。
public final void await() throws InterruptedException {
//await是可中断方法,当线程被打断后会抛出InterruptedException异常
if (Thread.interrupted())
throw new InterruptedException();
//将当前线程节点添加至等待队列尾部,并设置其节点的waitStatus为CONDITION
Node node = addConditionWaiter();
//释放所有的同步器状态,并返回state的值
int savedState = fullyRelease(node);
int interruptMode = 0;
//如果node不在同步等待队列中,则挂起当前线程
while (!isOnSyncQueue(node)) {
LockSupport.park(this);
//如果线程被打断了则退出循环
if ((interruptMode = checkInterruptWhileWaiting(node)) != 0)
break;
}
//如果node在同步等待队列中,则调用acquireQueued不断尝试获取同步器状态,如果acquireQueued返回中断标志为true且interruptMode不等于-1,则将interruptMode修改为1
if (acquireQueued(node, savedState) && interruptMode != THROW_IE)
interruptMode = REINTERRUPT;
//如果节点的nextWaiter不为空,则移除队列中不是CONDITION状态的节点
if (node.nextWaiter != null) // clean up if cancelled
unlinkCancelledWaiters();
//如果interruptMode不为0,则在await之后返回中断信息
if (interruptMode != 0)
reportInterruptAfterWait(interruptMode);
}
private void reportInterruptAfterWait(int interruptMode)
throws InterruptedException {
//如果interruptMode为-1,则抛出异常
if (interruptM