一、Condition作用
Condition 是一个多线程协调通信的工具类,可以让某些线程一起等待某个条件(condition)(等待其他线程唤醒),只有满足条件时,线程才会被唤醒。
二、Condition构造方法
使用ReentrantLock的继承AQS的内部类Sync一个方法
返回了AQS的内部类ConditionObject的一个对象。
三、ConditionObject
//condition queue的头指针和尾指针 private transient Node firstWaiter; private transient Node lastWaiter;
//从头开始遍历,将cancel状态的节点清理
private void unlinkCancelledWaiters() {
Node t = firstWaiter;
Node trail = null;
while (t != null) {
Node next = t.nextWaiter;
if (t.waitStatus != Node.CONDITION) {
t.nextWaiter = null;
if (trail == null)
firstWaiter = next;
else
trail.nextWaiter = next;
if (next == null)
lastWaiter = trail;
}
else
trail = t;
t = next;
}
}
addConditionWaiter()方法创建一个代表当前线程的Node到条件队列的尾部
private Node addConditionWaiter() {
Node t = lastWaiter;
// If lastWaiter is cancelled, clean out.
if (t != null && t.waitStatus != Node.CONDITION) {
// 如果节点不在条件队列中的话
// 从条件队列中清除已取消的节点的链接
unlinkCancelledWaiters();
t = lastWaiter;
}
// 创建一个hold住当前线程的Node节点
Node node = new Node(Thread.currentThread(), Node.CONDITION);
if (t == null)
firstWaiter = node;
else
t.nextWaiter = node;
lastWaiter = node;
return node;
}
await()方法:会释放锁资源以及CPU资源
public final void await() throws InterruptedException {
//如果当前线程的中断标识符是true,则将它的中断标识符设置为false,并返回true
//抛出中断异常,否则返回false
if (Thread.interrupted())
throw new InterruptedException();
// 1. 清除非CONDITION状态的节点,创建一个Node节点并将其添加到条件队列的尾部
Node node = addConditionWaiter();
// 2. 释放当前节点的独占模式占用情况,并且解除后继节点的阻塞状态
int savedState = fullyRelease(node);
int interruptMode = 0;
// 3. 判断是否不在同步队列中(head、tail)
while (!isOnSyncQueue(node)) {
// 不在同步队列中则挂起
// 直到其他线程调用unpark、中断时才解除休眠
LockSupport.park(this);
// checkInterruptWhileWaiting检查是否有中断,如果在信号之前中断,返回THROW_IE;如果在信号之后中断,返回REINTERRUPT;如果没有中断,返回0。
if ((interruptMode = checkInterruptWhileWaiting(node)) != 0)
break;
}
if (acquireQueued(node, savedState) && interruptMode != THROW_IE)
interruptMode = REINTERRUPT;
if (node.nextWaiter != null) // clean up if cancelled
unlinkCancelledWaiters();
if (interruptMode != 0)
reportInterruptAfterWait(interruptMode);
}
先插入AQS的CLH队列。这些线程通过CAS操作抢夺state,以表明是否成功抢占锁。
其中state为0表示当前没有线程获取锁。
fullyRelease()会释放该线程的所有锁,getState()会获取当前线程获取锁的次数。
final int fullyRelease(Node node) {
boolean failed = true;
try {
int savedState = getState();
if (release(savedState)) {
failed = false;
return savedState;
} else {
throw new IllegalMonitorStateException();
}
} finally {
if (failed)
node.waitStatus = Node.CANCELLED;
}
}
调用AQS的方法release尝试释放所有锁,释放成功,会将当前的AQS的FIFO同步队列的第一个Node元素唤醒(通过unparkSuccessor方法的LockSupport.unpark(s.thread)唤醒)。
public final boolean release(int arg) {
if (tryRelease(arg)) {
Node h = head;
if (h != null && h.waitStatus != 0)
unparkSuccessor(h);
return true;
}
return false;
}
调用的ReentrantLock中的tryRelease释放所有锁资源
protected final boolean tryRelease(int releases) {
int c = getState() - releases;
if (Thread.currentThread() != getExclusiveOwnerThread())
throw new IllegalMonitorStateException();
boolean free = false;
if (c == 0) {
free = true;
setExclusiveOwnerThread(null);
}
setState(c);
return free;
}
private void unparkSuccessor(Node node) {
int ws = node.waitStatus;
if (ws < 0)
compareAndSetWaitStatus(node, ws, 0);
Node s = node.next;
//如果第二个节点的waitStatus大于零,则为1表示节点被取消
//下面的if会找到离head节点最近的waitStatus等于-1的节点将其唤醒
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;
}
if (s != null)
LockSupport.unpark(s.thread);
}
判断是否在同步队列中
final boolean isOnSyncQueue(Node node) {
if (node.waitStatus == Node.CONDITION || node.prev == null)
return false;
if (node.next != null) // 如果存在后继则肯定在同步队列中
return true;
// node.prev 可以是非空的,但是因为CAS可能会失败所以还没有在队列中。
// 所以需要从tail开始遍历确保真实这样做的。
// 调用这个方法时,总是在tail附近,除非CAS失败了(不太可能),所以很少会遍历
return findNodeFromTail(node);
}
// 遍历,在同步队列中则返回true
private boolean findNodeFromTail(Node node) {
Node t = tail;
for (;;) {
if (t == node)
return true;
if (t == null)
return false;
t = t.prev;
}
}
signal()方法
public final void signal() {
// 检查独占模式下占有的线程是否为当前线程
if (!isHeldExclusively())
throw new IllegalMonitorStateException();
// 目标节点设置为等待队列中的头节点
Node first = firstWaiter;
if (first != null)
// 删除和传输节点,直到到达一个不可删除的节点或者null
doSignal(first);
}
private void doSignal(Node first) {
do {
// 1. 如果当前被通知信号的节点(等待队列中的头节点)的下一个节点为null的话,则尾节点置为null
if ( (firstWaiter = first.nextWaiter) == null)
lastWaiter = null;
// 2. 当前被通知信号的节点的下一个节点置为null
first.nextWaiter = null;
} while (!transferForSignal(first) &&
(first = firstWaiter) != null);
}
// 从条件队列传输一个节点到同步队列,成功则返回true
final boolean transferForSignal(Node node) {
// 如果无法变更waitStatus,说明节点已经被取消了
if (!compareAndSetWaitStatus(node, Node.CONDITION, 0))
return false;
// 将firstWaiter入队列,并且置为tail的后继
Node p = enq(node);
int ws = p.waitStatus;
if (ws > 0 || !compareAndSetWaitStatus(p, ws, Node.SIGNAL))
// 将tail置为Node.SIGNAL,并解除其后继即firstWaiter的阻塞状态
LockSupport.unpark(node.thread);
return true;
}
// 将节点入队列,必要时初始化
// head、tail 是同步队列的首尾节点
private Node enq(final Node node) {
for (;;) {
// 死循环处理
Node t = tail;
if (t == null) { // Must initialize
if (compareAndSetHead(new Node())) // tail为null,则表示同步队列是空的,初始化head节点
tail = head; // 并且tail设置和head一样
} else {
// 将firstWaiter的前置节点指向tail
node.prev = t;
if (compareAndSetTail(t, node)) {
// 将tial的后置指向firstWaiter并返回tail节点
t.next = node;
return t;
}
}
}
}
// 硬件级别的原子控制; headOffset表示head头的内存中的偏移位置
// 4各参数:对象、偏移位置、期望值、目标修改值
private final boolean compareAndSetHead(Node update) {
return unsafe.compareAndSwapObject(this, headOffset, null, update);
}
private final boolean compareAndSetTail(Node expect, Node update) {
return unsafe.compareAndSwapObject(this, tailOffset, expect, update);
}