Condition是一个接口,它主要是由awiat和singal方法组成,awiat方法是放弃自身锁,进入阻塞状态,等待信号进行唤醒,singal是唤醒线程,让线程去重新竞争锁。它和Object的wait和notify方法是一样的。在queue队列中就用到了condition,弄明白condition的原理,对于queue的认识我们可以更好的理解。
看一下Condition方法
void await() throws InterruptedException;
void awaitUninterruptibly();
long awaitNanos(long nanosTimeout) throws InterruptedException;
boolean awaitUntil(Date deadline) throws InterruptedException;
void signal();
void signalAll();
它的实现类是ConditionObject,存在于AbstractQueuedSynchronizer和AbstractQueuedLongSynchronizer中,我们看一下AbstractQueuedSynchronizer中ConditionObject的实现。
ConditionObject的属性
// 头节点
private transient Node firstWaiter;
// 尾节点
private transient Node lastWaiter;
Condition内部维护了一个由Node节点组成的单向链表,包括头节点和尾节点,这个链表的作用是存放等待signal信号的线程,线程被封装为Node节点。
await方法
public final void await() throws InterruptedException {
if (Thread.interrupted()) // 线程被中断后直接抛出异常,所以我们在调用这个方法的时候最好使用try...catch
throw new InterruptedException();
Node node = addConditionWaiter(); // 将当前线程封装成一个Node节点,加入到链表的尾端
int savedState = fullyRelease(node); // 释放当前线程占有的锁
int interruptMode = 0;
while (!isOnSyncQueue(node)) { // 遍历同步队列,看当前节点是否在队列中,如果不在,说明节点还不能去获取锁
LockSupport.park(this); // 挂起当前线程
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);
}
看一下await中具体方法的调用
private Node addConditionWaiter() {
Node t = lastWaiter; // 保存链表的尾节点
// 如果t不是null && t.ws不是CONDITION,调用unlinkCancelledWaiters取消当前节点
if (t != null && t.waitStatus != Node.CONDITION) {
unlinkCancelledWaiters();
t = lastWaiter; // 重新保存尾节点
}
Node node = new Node(Thread.currentThread(), Node.CONDITION); // 把当前线程的ws设为CONDITION,封装成一个Node
if (t == null) // 如果t为null,表示链表为空,就把当前节点设为头节点
firstWaiter = node;
else // t不为空,把t在condition队列上的next节点设为node
t.nextWaiter = node;
lastWaiter = node; // 改变引用,node设为尾节点
return node; // 返回该节点
}
把当前线程的状态设为CONDITION,封装成一个Node,把它添加到队列的尾部,如果当前队列尾节点不是CONDITION状态调用unlinkCancelledWaiters方法,从链表的头结点开始往后遍历,把状态不是CONDITION的节点全部移除.
再看一下unlinkCancelledWaiters方法
/**
* 从头往后遍历,移除队列中ws不为CONDITION的节点
*/
private void unlinkCancelledWaiters() {
Node t = firstWaiter; // 把当前队列的头节点赋给t
Node trail = null; // 设置一个空节点trail
while (t != null) { // 如果t不为null
Node next = t.nextWaiter; // 把t在等待队列上的下一个节点保存为next
if (t.waitStatus != Node.CONDITION) { // 如果t的ws不是CONDITION
t.nextWaiter = null; // t的nextwaiter设为null
if (trail == null) // trail为null,直接把next设为头节点
firstWaiter = next;
else // trail不为null,把next设为trail的nextwaiter
trail.nextWaiter = next;
if (next == null) // next为null,直接把trail设为尾节点
lastWaiter = trail;
}
else // 这是t的ws是CONDITION的情况,把t赋给trail
trail = t;
t = next; // 把next赋给t,继续循环
}
}
接着看一下fullRelease方法
/**
* 释放当前线程所占有的锁
* 释放失败直接抛出异常并且把当前node的ws设为CANCELLED
*/
final int fullyRelease(Node node) {
boolean failed = true; // 标志--默认表示释放失败
try {
int savedState = getState(); // 获取当前线程的状态
if (release(savedState)) { // release返回true,表示释放成功
failed = false; // failed设为false,表示释放成功
return savedState; // 直接返回当前节点的状态
} else { // release返回false,直接抛出异常
throw new IllegalMonitorStateException();
}
} finally {
if (failed) // 最后如果释放失败,要把node的ws设为CANCELLED
node.waitStatus = Node.CANCELLED;
}
}
通过getState方法获取当前线程的同步状态,使用release方法去释放当前线程占有的同步状态,释放成功,把释放后的状态返回.关于release方法在AQS框架分析中进行了阐述,这里不在细说.
继续往下走,看一下isOnSyncQueue方法
/**
* 这个方法主要是来检测node节点是否已经被转移到同步队列上,如果在同步队列上,直接返回true
*/
final boolean isOnSyncQueue(Node node) {
if (node.waitStatus == Node.CONDITION || node.prev == null) // node的ws=CONDITION或者node的prev=null,说明node在
return false; // condition队列上,直接返回false
if (node.next != null) // 如果node的next不为空,此时说明node必定在同步队列上,
return true; // 因为只有同步队列上的node才有next和prev的引用进行连接,所以直接返回true
/**
* node的prev可能不为null,但是它仍不在同步队列,可能正在使用CAS把它
* 设为尾节点,所以应该从同步队列的尾节点往前遍历,调用findNodeFromTail方法查找node
*/
return findNodeFromTail(node);
}
/**
* 从尾节点往前遍历,如果发现node在同步队列上,直接返回true
*/
private boolean findNodeFromTail(Node node) {
Node t = tail;
for (;;) {
if (t == node)
return true;
if (t == null)
return false;
t = t.prev;
}
}
我们使用isOnSyncQueue进行判定,如果返回true,表示当前线程已经进入同步队列,等待获取同步状态,代码继续往下执行;如果返回false,执行while循环,挂起当前线程,当前线程进入阻塞状态,执行checkInterruptWhileWaiting
/** Mode meaning to reinterrupt on exit from wait */
private static final int REINTERRUPT = 1;
/** Mode meaning to throw InterruptedException on exit from wait */
private static final int THROW_IE = -1;
private int checkInterruptWhileWaiting(Node node) {
return Thread.interrupted() ?
(transferAfterCancelledWait(node) ? THROW_IE : REINTERRUPT) :
0;
}
final boolean transferAfterCancelledWait(Node node) {
if (compareAndSetWaitStatus(node, Node.CONDITION, 0)) {
enq(node);
return true;
}
while (!isOnSyncQueue(node))
Thread.yield();
return false;
}
在挂起当前线程的过程中,如果线程未被中断,直接返回0,继续while循环;如果当前线程被中断,利用CAS把当前节点的ws设为0,表示线程中断先于唤醒,线程在得到唤醒之前就被中断,即中断在awiat过程中发生,此时会向外抛出异常,返回true告知调用的方法返回THROW_IE。如果当前线程不能使用CAS设置节点的状态,假设singal先发生,此时CAS会失败,等待唤醒信号直到被移动到同步队列,返回false告知上层方法返回REINTRRUPT。transferCancelledWait方法代表了线程因为中断而被唤醒。
重新梳理一下await方法:await是响应中断的,首先检查一下线程如果被中断,直接抛出异常,接着调用addConditionWaiter方法把当前节点加入到condition的队尾,紧着接调用fullyRelease释放当前线程所占有的锁,然后进行循环判定当前节点是否已经转到到同步队列,在循环过程中,还有调用checkInterruptWhileWaiting方法处理中断,break跳出循环。紧接着执行acquireQueued方法,该方法也在AQS框架中进行了分析,返回值为线程在等待得到同步状态的过程中是否被中断过,如果被中断过并且不需要在中断时抛出异常处理,那就把interruptMode = REINTERRUPT。如果被中断,但是node.nextWaiter != null,说明node还在condition队列中,代码执行到这里,线程必定已经进入同步队列中,再次调用unlinkCancelledWaiters方法清除condition队列上ws不CONDITION的节点。最后判断一下interruptMode的值,调用reportInterruptAfterWait方法进行处理。
private void reportInterruptAfterWait(int interruptMode)
throws InterruptedException {
if (interruptMode == THROW_IE)
throw new InterruptedException();
else if (interruptMode == REINTERRUPT)
selfInterrupt();
}
如果interruptMode=THROE_IE,说明线程在awiat中发生中断,必须抛出异常,如果interruptMode=REINTRRUPT,可能先得到唤醒信号后被中断,即线程再次获取同步状态后要进行自我中断一次。
awaitNanos
public final long awaitNanos(long nanosTimeout)
throws InterruptedException {
if (Thread.interrupted())
throw new InterruptedException();
Node node = addConditionWaiter();
int savedState = fullyRelease(node);
final long deadline = System.nanoTime() + nanosTimeout;
int interruptMode = 0;
while (!isOnSyncQueue(node)) {
if (nanosTimeout <= 0L) {
transferAfterCancelledWait(node);
break;
}
if (nanosTimeout >= spinForTimeoutThreshold)
LockSupport.parkNanos(this, nanosTimeout);
if ((interruptMode = checkInterruptWhileWaiting(node)) != 0)
break;
nanosTimeout = deadline - System.nanoTime();
}
if (acquireQueued(node, savedState) && interruptMode != THROW_IE)
interruptMode = REINTERRUPT;
if (node.nextWaiter != null)
unlinkCancelledWaiters();
if (interruptMode != 0)
reportInterruptAfterWait(interruptMode);
return deadline - System.nanoTime();
}
这个方法和await差不多,只不过加了时间限制,如果nanosTimeout >= spinForTimeoutThreshold,在nanosTimeout时间内挂起当前线程,每次循环都计算是否达到deadline,如果达到deadline,调用transferAfterCancelledWait方法,把当前线程从condition队列转移到同步队列,最后返回唤醒后的剩余等待时间。await(long time, TimeUnit unit)方法和这个方法类似,不过最后的返回值是true或false,记录的是transferAfterCancelledWait的返回值。
awaitUninterruptibly是忽略中断的,如果线程被中断,直接把interrupted=true,最后获取到同步状态后再进行自我中断。
public final void awaitUninterruptibly() {
Node node = addConditionWaiter();
int savedState = fullyRelease(node);
boolean interrupted = false;
while (!isOnSyncQueue(node)) {
LockSupport.park(this);
if (Thread.interrupted())
interrupted = true;
}
if (acquireQueued(node, savedState) || interrupted)
selfInterrupt();
}
signal
public final void signal() {
if (!isHeldExclusively()) // 判断当前线程是否为独占锁
throw new IllegalMonitorStateException();
Node first = firstWaiter; // 利用doSingal方法唤醒condition队列中的第一个线程
if (first != null)
doSignal(first);
}
singal为唤醒condition队列上的头节点的线程,其中isHeldExclusively方法是需要子类去重写的,如果当前线程不是独占线程,直接抛出异常,接着调用doSingal方法。
private void doSignal(Node first) {
do {
if ( (firstWaiter = first.nextWaiter) == null)
lastWaiter = null;
first.nextWaiter = null;
} while (!transferForSignal(first) &&
(first = firstWaiter) != null);
}
final boolean transferForSignal(Node node) {
if (!compareAndSetWaitStatus(node, Node.CONDITION, 0))
return false;
Node p = enq(node);
int ws = p.waitStatus;
if (ws > 0 || !compareAndSetWaitStatus(p, ws, Node.SIGNAL))
LockSupport.unpark(node.thread);
return true;
}
调用transferForSignal去唤醒first的ws,如果利用CAS不能把node的ws设为0,直接返回false,表示线程放弃等待,如果成功,通过自旋把node加入到同步队列,返回值是node的前继节点p,p的ws>0 或者不能使用CAS把p的ws设为singal,表示p已经被取消,此时直接释放node代表的线程,直接返回true,表示唤醒的线程加入同步队列去竞争同步状态了。signalAll是唤醒condition队列上的所有等待线程,它调用的dosingalAll方法会循环唤醒队列中的头节点,直接队列为空。虽然这个类就主要实现了await和singal这两个方法,但是涉及的方法很多,设计的知识点比较深,我也是当时看了很久想了很久,所以要坚持下去,毕竟努力就有收获。