流程
当调用wait 方法的时候从拿到一个最新创建的Node并加入 Condition 队列
唤醒AQS队列中的一个线程
判断node是否在aqs 队列上
如果不在的话将当前线程阻塞
当调用signal方法的时候会唤醒指定的线程 并添加当前节点到AQS队列
wait()
public final void await() throws InterruptedException {
if (Thread.interrupted())
throw new InterruptedException();
//添加一个节点到Condition 队列中 如果没有则创建放到尾节点 尾插法 节点状态为 condtition
Node node = addConditionWaiter();
//释放当前的锁 得到锁的状态 并唤醒处于 aqs队列的一个线程
long savedState = fullyRelease(node);
int interruptMode = 0;
//判断一个节点是否在aqs队列上
while (!isOnSyncQueue(node)) {
//如果在 park自己阻塞等待
LockSupport.park(this);
//判断自己是否被中断
if ((interruptMode = checkInterruptWhileWaiting(node)) != 0)
break;
}
//尝试获取锁
if (acquireQueued(node, savedState) && interruptMode != THROW_IE)
interruptMode = REINTERRUPT;
//如果node 的下一个节点不是null 清理condition队列上的节点
if (node.nextWaiter != null) // clean up if cancelled
unlinkCancelledWaiters();
if (interruptMode != 0)
//线程中断抛异常
reportInterruptAfterWait(interruptMode);
}
创建Node 节点并加入Condition队列中(单向链表)
如果node 是空则创建一个新的node状态为 CONDITION并设置成尾节点
如果不是空并且节点状态不是 CONDITION 则从链表中删除 然后直接返回尾节点
如果不是空节点并且节点状态是 CONDITION 则把尾节点的下一个节点设置成刚构建好的节点
private Node addConditionWaiter() {
//拿到尾节点
Node t = lastWaiter;
// If lastWaiter is cancelled, clean out.
//如果尾节点不等于空 并且尾节点的状态不是 CONDITION
if (t != null && t.waitStatus != Node.CONDITION) {
unlinkCancelledWaiters();
t = lastWaiter;
}
//构建一个节点 节点状态为 CONDITION
Node node = new Node(Thread.currentThread(), Node.CONDITION);
if (t == null)
//如果尾节点== null 把构建的节点设置成尾节点
firstWaiter = node;
else
//否则把前一个节点的next指针指向构建的节点
t.nextWaiter = node;
//把刚构建的节点设置成尾节点
lastWaiter = node;
return node;
}
删除不是CONDITION状态的节点
private void unlinkCancelledWaiters() {
Node t = firstWaiter;
Node trail = null;
// 如果首节点不为空
while (t != null) {
// 获取到下个节点
Node next = t.nextWaiter;
// 如果该节点的状态不等于conditon,则该节点需要在链表中删除
if (t.waitStatus != Node.CONDITION) {
// 该节点的下个节点设置为空,意味着垃圾回收后就回收该节点
t.nextWaiter = null;
// trail 为空,则把下一个节点负责给首节点
if (trail == null)
firstWaiter = next;
else
// 把下一个节点赋值给next,这样链表就要继续连接起来
trail.nextWaiter = next;
if (next == null)
lastWaiter = trail;
}
// 等于condtion,把该节点赋值给尾节点
else
trail = t;
// 下个一个节点赋值给t,进行下一次循环
t = next;
}
}
唤醒AQS队列中的一个线程
final long fullyRelease(Node node) {
boolean failed = true;
try {
//拿当前锁的状态值
long savedState = getState();
//释放锁
if (release(savedState)) {
failed = false;
return savedState;
} else {
throw new IllegalMonitorStateException();
}
} finally {
if (failed)
node.waitStatus = Node.CANCELLED;
}
}
protected final boolean tryRelease(int releases) {
//state -1
int c = getState() - releases;
if (Thread.currentThread() != getExclusiveOwnerThread())
throw new IllegalMonitorStateException();
boolean free = false;
if (c == 0) {
//如果c =0 表示当前是无锁状态 把线程iq清空
free = true;
setExclusiveOwnerThread(null);
}
//重新设置 state
setState(c);
return free;
}
private void unparkSuccessor(Node node) {
/*
* If status is negative (i.e., possibly needing signal) try
* to clear in anticipation of signalling. It is OK if this
* fails or if status is changed by waiting thread.
*/
int ws = node.waitStatus;
if (ws < 0)
//设置head节点的状态为0
compareAndSetWaitStatus(node, ws, 0);
/*
* Thread to unpark is held in successor, which is normally
* just the next node. But if cancelled or apparently null,
* traverse backwards from tail to find the actual
* non-cancelled successor.
*/
//拿到head节点的下一个节点
Node s = node.next;
//如果下一个节点为null 或者 status>0则表示是 CANCELLED 状态
//听过尾部节点开始扫描 找到距离 head最近的一个 waitStatus<=0的节点
if (s == null || s.waitStatus > 0) {
s = null;
for (Node t = tail; t != null && t != node; t = t.prev)
if (t.waitStatus <= 0)
s = t;
}
//如果next 节点不等于空直接唤醒这个线程
if (s != null)
LockSupport.unpark(s.thread);
}
判断当前节点是否在同步队列中,返回 false 表示不在,返回true 表示如果不在,将当前线程挂起
final boolean isOnSyncQueue(Node node) {
// 如果状态是condition,证明一定不再同步队列里,condition状态只存在于等待队列,在同步队列里,node.prev是一定不为空的,因为有个head的节点
if (node.waitStatus == Node.CONDITION || node.prev == null)
return false;
// 在等待队列里,node.next 是等于空的,不等于空就是在同步队列当中
if (node.next != null) // If has successor, it must be on queue
return true;
// 遍历正个同步队列,判断node是否在同步队列当中
return findNodeFromTail(node);
}
比如由于线程A调用了await 方法然后进入阻塞状态并唤醒了处于aqs 队列中的线程B此时线程B执行调用 signal 会唤醒处于 Condition 队列中阻塞等待的节点
signal
public final void signal() {
// 判断当前线程是否获取到了锁,如果没有抛异常
if (!isHeldExclusively())
throw new IllegalMonitorStateException();
Node first = firstWaiter;
// 如果首节点不为空,唤醒首节点
if (first != null)
doSignal(first);
}
doSignal
private void doSignal(Node first) {
do {
// frist的下一个节点如果为空,就把lastWaiter设置为空
if ( (firstWaiter = first.nextWaiter) == null)
lastWaiter = null;
// 不为空,再把first 节点从等待队列中移除
first.nextWaiter = null;
} while (!transferForSignal(first) &&
// 返回false,firstWaiter已经被从新赋值过了,如果不是空,进行下一次遍历
(first = firstWaiter) != null);
}
transferForSignal
final boolean transferForSignal(Node node) {
// 如果该节点不是condition状态(可能编程了cancelled状态),waitStatus=0,就会设置失败,返回false
if (!compareAndSetWaitStatus(node, Node.CONDITION, 0))
return false;
// 将该节点放入到AQS队列中
Node p = enq(node);
int ws = p.waitStatus;
// 如果上一个节点状态没有被改变,也就是没有编程cancelled状态,就将该节点状态设置成singal状态
if (ws > 0 || !compareAndSetWaitStatus(p, ws, Node.SIGNAL))
// 如果状态已经是cancelled状态,将该节点的线程挂起
LockSupport.unpark(node.thread);
return true;
}