获取独占标志位
public final void acquire(int arg) {
//尝试获取锁失败后,当前请求构造node节点添加到同步队列中,然后自旋逻辑锁
if (!tryAcquire(arg) &&
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
selfInterrupt();
}
获取独占锁的核心逻辑
final boolean acquireQueued(final Node node, int arg) {
boolean failed = true;
try {
boolean interrupted = false;
//开始自旋
for (;;) {
final Node p = node.predecessor();
//如果当前请求的前置节点为头节点,开始尝试获取锁,
if (p == head && tryAcquire(arg)) {
//获取锁成功-》设置当前节点为头节点
setHead(node);
//之前的头节点断开后续节点,方便gc回收。
p.next = null; // help GC
failed = false;
return interrupted;
}
//如果前置节点waitStatus状态为SIGNAL,那么线程处理等待状态
if (shouldParkAfterFailedAcquire(p, node) &&
parkAndCheckInterrupt())
interrupted = true;
}
} finally {
if (failed)
cancelAcquire(node);
}
}
shouldParkAfterFailedAcquire 判断当前线程是否需要陷入等待
private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) {
int ws = pred.waitStatus;
if (ws == Node.SIGNAL)
//如果前置节点waitStatus状态为signal,标识前置节点释放时会唤醒当前节点,那么就陷入等待,等待前置节点唤醒即可
return true;
if (ws > 0) {
//如果前置节点为退出的状态,那么就将这些节点断开,继续自旋,
//下一次继续执行shouldParkAfterFailedAcquire判断方法,
do {
node.prev = pred = pred.prev;
} while (pred.waitStatus > 0);
pred.next = node;
} else {
//如果节点为0、PROPAGATE,那么就将前置节点置为SIGNAL,继续自旋。
//下一次继续执行shouldParkAfterFailedAcquire判断方法,
//下一次进入的话,判断为SIGNAL,那么说明前面的节点释放时会唤醒这个节点。
//waitStatus为0,可能是获取到了同步标识位,没有设置node节点到队列中
compareAndSetWaitStatus(pred, ws, Node.SIGNAL);
}
return false;
}
主线逻辑:尝试获取独占标识位失败-》当前请求添加到同步队列的尾部-》自旋获取锁-》当前节点前置节点为头节点,尝试获取锁-》
判断头节点后面是否有节点在等待
public final boolean hasQueuedPredecessors() {
// The correctness of this depends on head being initialized
// before tail and on head.next being accurate if the current
// thread is first in queue.
Node t = tail; // Read fields in reverse initialization order
Node h = head;
Node s;
//(s = h.next) == null head和tail有可能刚刚完成初始化,tail还没指向新添加的节点。
return h != t &&
((s = h.next) == null || s.thread != Thread.currentThread());
}
释放独占锁
public final boolean release(int arg) {
//尝试释放锁
if (tryRelease(arg)) {
Node h = head;
if (h != null && h.waitStatus != 0)
//唤醒后续节点
unparkSuccessor(h);
return true;
}
return false;
}
主线逻辑:释放同步标志为-》唤醒后续节点。
获取共享标志位
核心代码
private void doAcquireShared(int arg) {
//构造共享节点。
final Node node = addWaiter(Node.SHARED);
boolean failed = true;
try {
boolean interrupted = false;
for (;;) {
final Node p = node.predecessor();
if (p == head) {
//前置节点位头节点,尝试获取锁
int r = tryAcquireShared(arg);
if (r >= 0) {
//设置头节点-》唤醒后续节点去获取共享锁
setHeadAndPropagate(node, r);
p.next = null; // help GC
if (interrupted)
selfInterrupt();
failed = false;
return;
}
}
//如下和共享锁的中逻辑一样
if (shouldParkAfterFailedAcquire(p, node) &&
parkAndCheckInterrupt())
interrupted = true;
}
} finally {
if (failed)
cancelAcquire(node);
}
}
主线逻辑:构造共享节点-》进入自旋-》如果前置节点为头节点-》尝试获取共享状态-》设置当前节点为头节点-》设置头节点waitStaus状态为0-》唤醒后续节点
释放共享节点
doReleaseShared
private void doReleaseShared() {
for (;;) {
Node h = head;
if (h != null && h != tail) {
int ws = h.waitStatus;
//如下是acquireShared调用的。
if (ws == Node.SIGNAL) {
if (!compareAndSetWaitStatus(h, Node.SIGNAL, 0))
continue; // loop to recheck cases
//唤醒后续节点
unparkSuccessor(h);
}
else if (ws == 0 &&
!compareAndSetWaitStatus(h, 0, Node.PROPAGATE))
//理论上头节点的waitStatus应该为SIGNAL,因为后续节点执行shouldParkAfterFailedAcquire将前置节点置为SIGNAL。
//这里ws==0说明头节点是刚刚成为的,然后立刻新来了一个节点,还没有执行完shouldParkAfterFailedAcquire方法。
//!compareAndSetWaitStatus(h, 0, Node.PROPAGATE)为true,说明头节点的waitStatu改变了。即后续节点执行了
//shouldParkAfterFailedAcquire方法,waitStatus应该为SIGNAL了。所以继续循环。
//!compareAndSetWaitStatus(h, 0, Node.PROPAGATE)为false,后续节点还没执行shouldParkAfterFailedAcquire,
//头节点当前为PROPAGATE,那么后续节点执行shouldParkAfterFailedAcquire将后续节点waitStatus状态改为SIGNAL。
continue; // loop on failed CAS
}
if (h == head) // loop if head changed
break;
}
}
主线逻辑:释放共享标志位成功-》唤醒后续节点,
参考:https://segmentfault.com/a/1190000016447307
-------------------------------------------------------条件等待-----------------------------------------------------------
线程陷入等待状态,等待唤醒
public final long awaitNanos(long nanosTimeout)
throws InterruptedException {
if (Thread.interrupted())
throw new InterruptedException();
// 将当前线程添加到条件队列中,waitStatus为CONDITION
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)
//移除条件队列中已经退出的节点。即waitStatus不等于-2的节点。
unlinkCancelledWaiters();
if (interruptMode != 0)
//向外抛异常或者设置中断标识。
reportInterruptAfterWait(interruptMode);
return deadline - System.nanoTime();
}
关于异常的方法
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.
*/
//执行上面的cas失败,那就是在被唤醒之后执行的,唤醒线程马上就会把节点添加到同步队列中,等待一下即可。
while (!isOnSyncQueue(node))
Thread.yield();
return false;
}
等待主线逻辑:添加节点到条件队列-》是否锁-》检查是否在同步队列中,陷入等待,等待唤醒-》重新获取锁。
唤醒到该节点后会将节点同步到同步队列,所以这边就是检查当前节点是否被同步到了同步队列中,如果同步到了同步队列,则开始获取同步锁。
唤醒
public final void signal() {
if (!isHeldExclusively())
throw new IllegalMonitorStateException();
Node first = firstWaiter;
if (first != null)
doSignal(first);
}
唤醒的核心代码
final boolean transferForSignal(Node node) {
//CAS失败,说明该节点的线程已经退出了。
if (!compareAndSetWaitStatus(node, Node.CONDITION, 0))
return false;
//将该节点从条件队列移动到同步队列
Node p = enq(node);
int ws = p.waitStatus;
//前置节点已经退出,或者前置节点设置Signal标志异常,那么唤醒等待的线程
if (ws > 0 || !compareAndSetWaitStatus(p, ws, Node.SIGNAL))
LockSupport.unpark(node.thread);
return true;
}
唤醒方法做了三件主要的事情
1 修改waitStatus状态为0
2 将节点从条件队列移动到同步队列
3 如果前置节点已经退出,或者前置节点设置Signal标志异常,那么唤醒等待的线程。
未完待续。。。