await
public final void await() throws InterruptedException {
// 1.如果当前线程被中断,则抛出中断异常
if (Thread.interrupted())
throw new InterruptedException();
// 2.创建一个线程的节点,并放到Condition队列中去,等待着signal来唤起它
Node node = addConditionWaiter();
// 3.调用tryRelease,释放当前线程的锁,这样别的线程可以获取锁,不会出现死锁了
long savedState = fullyRelease(node);
int interruptMode = 0;
// 4. 判断当前现在是不是在等待锁的队列中。如果不在,就park当前线程(这个时候说明线程还在等signal,就不线程给阻塞了,等待signal),如果在,就退出循环,这个时候如果被中断,那么就退出循环
while (!isOnSyncQueue(node)) {
LockSupport.park(this);
if ((interruptMode = checkInterruptWhileWaiting(node)) != 0)
break;
}
// 5.这个时候线程已经被signal()或者signalAll()操作给唤醒了,退出了4中的while循环,这里就尝试去获得锁。
if (acquireQueued(node, savedState) && interruptMode != THROW_IE)
interruptMode = REINTERRUPT;
if (node.nextWaiter != null)
unlinkCancelledWaiters();
if (interruptMode != 0)
reportInterruptAfterWait(interruptMode);
}
让当前线程等待在条件上
private Node addConditionWaiter() {
Node t = lastWaiter;
// If lastWaiter is cancelled, clean out.
if (t != null && t.waitStatus != Node.CONDITION) {
unlinkCancelledWaiters();
t = lastWaiter;
}
Node node = new Node(Thread.currentThread(), Node.CONDITION);
if (t == null)
firstWaiter = node;
else
t.nextWaiter = node;
lastWaiter = node;
return node;
}
首先看链表的最后一个节点的状态是不是为Node.CONDITION,如果不是的,那么就清理下整个链表中的非condition状态的节点,然后利用当前线程创建一个节点并放到链表的最后,并返回节点。
我们在看下清理链表的代码
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;
}
}
这个函数就是遍历整个链表,把链表中状态不是Node.CONDITION的线程节点给删除。保证所有的线程都是等待这个条件的。
释放锁
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;
}
}
调用release释放锁,如果释放不成功,把node.waitstatus=cancelled,表示线程不需要等待了。
public final boolean release(int arg) {
if (tryRelease(arg)) {
Node h = head;
if (h != null && h.waitStatus != 0)
unparkSuccessor(h);
return true;
}
return false;
}
首先尝试去释放锁,如果成功唤起一个等待的线程
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;
}
可重入锁通过status 表示当前线程获取几次锁,这个需要释放锁的话,就是需要把减去releases, 后面有个判断获得锁的线程释放当前线程(当然是的,否则怎么释放呢?)。 然后看减去后是否为0,如果0的话,释放成功并把当前锁的线程设置为null。设置状态并返回是否释放成功。
然后看下unparkSuccessor
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)
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.
*/
Node s = node.next;
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) // If has successor, it must be on queue
return true;
/*
* node.prev can be non-null, but not yet on queue because
* the CAS to place it on queue can fail. So we have to
* traverse from tail to make sure it actually made it. It
* will always be near the tail in calls to this method, and
* unless the CAS failed (which is unlikely), it will be
* there, so we hardly ever traverse much.
*/
return findNodeFromTail(node);
}
看node对应的线程是否在同步队列中的:
- 如果线程状态是CONDITION,也就是还没有收到signal消息,肯定不会去竞争锁的,一定不在同步队列中。 如果不是CONDITION,那么就看下prev,如果是空的,一定不在队列中
- 看下next非空,也就是有后续的节点,那一定已经放到了队列中了
- 走到了这里,条件一和二都不成立,应该是线程拿到了signal信号,而尝试把节点放到队列后面去的时候,cas失败还在尝试中,现在如果好了的话,那么节点一定排在很后面,我们就从后往前去便利链表。
private boolean findNodeFromTail(Node node) {
Node t = tail;
for (;;) {
if (t == node)
return true;
if (t == null)
return false;
t = t.prev;
}
}
线程阻塞后被唤起,我们判断是不是被中断了,如果是中断了,那么就跳出循环,否则还在循环里面
private int checkInterruptWhileWaiting(Node node) {
return Thread.interrupted() ?
(transferAfterCancelledWait(node) ? THROW_IE : REINTERRUPT) :
0;
}
如果真的被中断了,那么尝试把节点的状态从condition到0,并把节点放到同步队列最后去
final boolean transferAfterCancelledWait(Node node) {
if (compareAndSetWaitStatus(node, Node.CONDITION, 0)) {
enq(node);
return true;
}
/*
* If we lost out to a signal(), then we can't proceed
* until it finishes its enq(). Cancelling during an
* incomplete transfer is both rare and transient, so just
* spin.
*/
while (!isOnSyncQueue(node))
Thread.yield();
return false;
}