给大家推荐个靠谱的公众号程序员探索之路,大家一起加油
目录
checkInterruptWhileWaiting(node)
transferAfterCancelledWait(node)
Condition
Condition提供await,signal,signalAll方法,和线程的wait,notify,notifyAll类似
属性
public class ConditionObject implements Condition, java.io.Serializable {
private static final long serialVersionUID = 1173984872572414699L;
//头结点
private transient Node firstWaiter;
//尾节点
private transient Node lastWaiter;
Node和上面的node是同一个,只不过这里没有用其他属性,只是用了
Node nextWaiter;
标记当前Node的下一个节点
所以Condition维护的是一个单向队列,当符合条件时会唤醒队列中的节点,所以叫它条件队列,一个ReentranLock对应的可以有很多个condition,每一个condition都有一个条件队列
等待condition.await()
位置:AbstractQueuedSynchronizer 2032
方法目的:
方法流程
public final void await() throws InterruptedException {
if (Thread.interrupted())
throw new InterruptedException();
Node node = addConditionWaiter();
int savedState = fullyRelease(node);
int interruptMode = 0;
// isOnSyncQueue(node) 判断node节点是不是 在阻塞队列中了
//第一次进入循环时 node肯定不在 所以线程挂起 signal唤醒线程时
//会把节点加入到阻塞队列中 然后唤醒 就会从while循环中退出
//或者线程中断了也会退出循环
while (!isOnSyncQueue(node)) {
LockSupport.park(this);
if ((interruptMode = checkInterruptWhileWaiting(node)) != 0)
break;
}
if (acquireQueued(node, savedState) && interruptMode != THROW_IE)
interruptMode = REINTERRUPT;
//signal 将条件队列中 的node转移到阻塞队列中 而且 first.nextWaiter = null 但是如果是signal之前出现中断了 node也是会进入阻塞队列的 但是 node.nextWaiter没有处理 所以下面会处理 取消的节点
if (node.nextWaiter != null) // clean up if cancelled
//去除节点 纯链表操作
unlinkCancelledWaiters();
//处理中断
if (interruptMode != 0)
reportInterruptAfterWait(interruptMode);
}
addConditionWaiter()
位置:AbstractQueuedSynchronizer 1848
方法目的:将节点添加到条件队列中
方法流程:
- 判断条件队尾是否是取消状态
- 进条件队列
private Node addConditionWaiter() {
Node t = lastWaiter;
// If lastWaiter is cancelled, clean out.
// t.waitStatus != Node.CONDITION 因为条件队列的waitStatus初始化就是Node.CONDITION
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;
}
位置:AbstractQueuedSynchronizer 1719
方法目的:完成释放锁(独占锁 后面会介绍共享锁)
方法流程:
- 完全释放锁
- 如果失败 标记当前节点为取消 release和上面的释放锁是一样的
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;
}
}
isOnSyncQueue(node)
位置:AbstractQueuedSynchronizer 1631
方法目的:判断节点是否在 阻塞队列中
方法流程:
final boolean isOnSyncQueue(Node node) {
//节点waitStatus 是Node.CONDITION或者 前驱为null 没有进入阻塞队列
if (node.waitStatus == Node.CONDITION || node.prev == null)
return false;
//后继为不为null 那么 节点进入阻塞队列了
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.
*/
//这个方法就是从阻塞队列的队尾找 看node是否在队列中
return findNodeFromTail(node);
}
到这里线程挂起了 那么我们先看到 signal()唤醒方法
唤醒condition.signal()
位置:AbstractQueuedSynchronizer 1937
方法目的:将等待队列队头加入到阻塞队列中竞争锁
方法流程:
public final void signal() {
//检查获取锁的线程是否是当前线程
if (!isHeldExclusively())
throw new IllegalMonitorStateException();
Node first = firstWaiter;
if (first != null)
doSignal(first);
}
位置:AbstractQueuedSynchronizer 1870
方法目的:将等待队列队头加入到阻塞队列中
方法流程:
private void doSignal(Node first) {
do {
if ( (firstWaiter = first.nextWaiter) == null)
lastWaiter = null;
first.nextWaiter = null;
} while (!transferForSignal(first) &&
(first = firstWaiter) != null);
}
transferForSignal(first)
位置:AbstractQueuedSynchronizer 1670
方法目的:将node加入到阻塞队列
方法流程:
final boolean transferForSignal(Node node) {
/*
* If cannot change waitStatus, the node has been cancelled.
*/
//上面的解释很清楚 如果 waitStatus 不能从 CONDITIONcas成0 代表该几点已经被取消了
if (!compareAndSetWaitStatus(node, Node.CONDITION, 0))
return false;
/*
* Splice onto queue and try to set waitStatus of predecessor to
* indicate that thread is (probably) waiting. If cancelled or
* attempt to set waitStatus fails, wake up to resync (in which
* case the waitStatus can be transiently and harmlessly wrong).
*/
//进入阻塞队列 返回的是node的前驱节点
Node p = enq(node);
int ws = p.waitStatus;
//如果 ws > 0 说明前驱节点 取消了 那么node节点直接唤醒
//如果把前驱节点的waitSatus设置为Signal失败那么 也直接唤醒
//大多数情况下 ws是 <= 0 的 而且 cas 前驱的waitStatus为SIGNAL
//为什么可以直接唤醒 因为 唤醒之后还是会请求锁的 请求不到还是会挂起
//只不过是 在请求不到锁的地方挂起
//这里如果前驱节点是取消的 直接唤醒的好处 万一 前驱节点的前驱是head呢
if (ws > 0 || !compareAndSetWaitStatus(p, ws, Node.SIGNAL))
LockSupport.unpark(node.thread);
return true;
}
唤醒之后:
public final void await() throws InterruptedException {
if (Thread.interrupted())
throw new InterruptedException();
Node node = addConditionWaiter();
int savedState = fullyRelease(node);
int interruptMode = 0;
while (!isOnSyncQueue(node)) {
//在这里挂起了 唤醒之后发现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);
}
checkInterruptWhileWaiting(node)
位置:AbstractQueuedSynchronizer 2001
方法目的:检查node所在的线程是否中断了
方法流程:
private int checkInterruptWhileWaiting(Node node) {
return Thread.interrupted() ?
(transferAfterCancelledWait(node) ? THROW_IE : REINTERRUPT) :
0;
}
transferAfterCancelledWait(node)
位置:AbstractQueuedSynchronizer 1697
方法目的:检测节点是在signal 之前还是之后中断的
方法流程:
无论是在哪里中断的 都会进入到阻塞队列中
final boolean transferAfterCancelledWait(Node node) {
//如果能cas成功说明是 signal之前中断的 因为signal会把节点的waitStatus设置为0
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.
*/
//走到这一步的时候 就是上面的 cas waitStatus失败 那就是signal把waitStatus 设置成了0 这里如果node还没有在阻塞队列中说明是 在自旋加入队列中 这里放弃时间片
while (!isOnSyncQueue(node))
Thread.yield();
return false;
}
interruptMode的取值
//从英文解释也是很好理解的REINTERRUPT表示需要重新设置中断状态
THROW_IE表示需要抛出中断异常
interruptMode = 0 表示没有出现中断
/** 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;
带有超时时间的await
位置:AbstractQueuedSynchronizer 2147
方法目的:
方法流程:
public final boolean await(long time, TimeUnit unit)
throws InterruptedException {
//将传入的时间 转成纳秒
long nanosTimeout = unit.toNanos(time);
if (Thread.interrupted())
throw new InterruptedException();
//添加到等待队列
Node node = addConditionWaiter();
//完全释放锁
int savedState = fullyRelease(node);
final long deadline = System.nanoTime() + nanosTimeout;
//是否超时标志位
boolean timedout = false;
int interruptMode = 0;
while (!isOnSyncQueue(node)) {
if (nanosTimeout <= 0L) {
//返回 true 说明是转移到 阻塞队列成功 那也就是没有超时
//返回false 说明在 signal 唤醒之前没有进入到阻塞队列中 那就是超时嘛
timedout = transferAfterCancelledWait(node);
break;
}
//等待时间超过 1秒 就挂起 如果不是就自旋
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 !timedout;
}
唤醒所有的方法SignalAll
位置:AbstractQueuedSynchronizer 1952
方法目的:唤醒所有等待节点
方法流程:
public final void signalAll() {
if (!isHeldExclusively())
throw new IllegalMonitorStateException();
Node first = firstWaiter;
if (first != null)
doSignalAll(first);
}
//这里和 单个的signal不一样的地方就是 循环 条件队列
private void doSignalAll(Node first) {
lastWaiter = firstWaiter = null;
do {
Node next = first.nextWaiter;
first.nextWaiter = null;
transferForSignal(first);
first = next;
} while (first != null);
}