有一说一,AQS实在是太复杂了,但我觉得自己勉强还是可以来写个回答。
首先是得说LockSupport,LockSupport主要的API就是park和unpark,其实这个类就是对Unsafe的park和unpark的简单封装而已,除此之外还可以用一个blocker 来记录一些和park的发起者有关的信息。这个blocker对于park和unpark来说似乎并没有必要的意义。
package jdk.internal.misc;
public final class Unsafe {
public native void unpark(Object thread);
public native void park(boolean isAbsolute, long time);
}
Unsafe的实现在这里就不去详细展开了,毕竟已经涉及到了Native层。
这里要注意park和unpark这一组API有一些特殊的地方在于,假如在一个线程已经start之后但并未被park的状态下被unpark,那么下一次park将不会导致挂起。除此之外,假如在park的时候因interrupt而返回,那么这是不会抛出InterruptedException的,需要用interrupted自行处理。
这个LockSupport的功能其实很基础,它的代码很短,它就是用来挂起或唤醒线程的。但是题主你所提到的那些,执行过程,那可真是说来话长了。
要是想讲清楚Condition,那么首先就要说到Lock。我们常用的一种Lock就是ReentrantLock,也就是可重入锁:
public class ReentrantLock implements Lock, java.io.Serializable {
private final Sync sync;
abstract static class Sync extends AbstractQueuedSynchronizer {
abstract void lock();
final boolean nonfairTryAcquire(int acquires) {
final Thread current = Thread.currentThread();
int c = getState();
if (c == 0) {
if (compareAndSetState(0, acquires)) {
setExclusiveOwnerThread(current);
return true;
}
}
else if (current == getExclusiveOwnerThread()) {
int nextc = c + acquires;
if (nextc < 0) // overflow throw new Error("Maximum lock count exceeded");
setState(nextc);
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;
}
final ConditionObject newCondition() {
return new ConditionObject();
}
}
static final class NonfairSync extends Sync {
final void lock() {
if (compareAndSetState(0, 1))
setExclusiveOwnerThread(Thread.currentThread());
else
acquire(1);
}
protected final boolean tryAcquire(int acquires) {
return nonfairTryAcquire(acquires);
}
}
static final class FairSync extends Sync {
final void lock() {
acquire(1);
}
protected final boolean tryAcquire(int acquires) {
final Thread current = Thread.currentThread();
int c = getState();
if (c == 0) {
if (!hasQueuedPredecessors() &&
compareAndSetState(0, acquires)) {
setExclusiveOwnerThread(current);
return true;
}
}
else if (current == getExclusiveOwnerThread()) {
int nextc = c + acquires;
if (nextc < 0)
throw new Error("Maximum lock count exceeded");
setState(nextc);
return true;
}
return false;
}
}
public ReentrantLock() {
sync = new NonfairSync();
}
public ReentrantLock(boolean fair) {
sync = fair ? new FairSync() : new NonfairSync();
}
public void lock() {
sync.lock();
}
public void unlock() {
sync.release(1);
}
public Condition newCondition() {
return sync.newCondition();
}
}
这个类里面绝大多数的代码已经被我忽略,但是已经足够表述清楚,lock、unlock、newCondition实际上是依赖AbstractQueuedSynchronizer的acquire、release、newCondition,LockSupport其实代码也很短,没比LockSupport长多少。
那么接下来要讲得就是java.util.concurrent.locks这个包里头最难啃的一块硬骨头,它就是AbstractQueuedSynchronizer,这是整个包的核心,它的代码行数是这个包里最多的。
首先看一下acquire和release:
public abstract class AbstractQueuedSynchronizer
extends AbstractOwnableSynchronizer
implements java.io.Serializable {
private volatile int state;
public final void acquire(int arg) {
if (!tryAcquire(arg) &&
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
selfInterrupt();
}
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 boolean tryAcquire(int arg) {
throw new UnsupportedOperationException();
}
protected boolean tryRelease(int arg) {
throw new UnsupportedOperationException();
}
}
初看这段代码时我觉得有点莫名其妙无从下手,不过如果想明白了AQS的原理,那么其实上面这段代码就不难理解了。
首先为了互斥锁的可重入性,需要有一个数字来记录这个锁的被重入深度,就是这里的state,其次需要一个阻塞队列来记录所有正在请求中的线程,在一个线程因请求失败而被挂起之前需要先入队,当一个线程在被另一个线程唤醒之后要出队。
tryAcquire和tryRelease是由AbstractQueuedSynchronizer的子类实现的,用于修改state, 入队与出队分别在addWaiter和acquireQueued中,而挂起与唤醒则分别在acquireQueued和unparkSuccessor里。
只有先把这些理清楚,才有可能明白题主你所提到的那段代码。
注意一下ReentrantLock的newCondition,把这篇回答向上翻一翻,会发现其实现类是个ConditionObject,这是AbstractQueuedSynchronizer的非静态内部类,题主所贴出来的就是它的await方法。
public class ConditionObject implements Condition, java.io.Serializable {
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)) {
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);
}
public final void signal() {
if (!isHeldExclusively())
throw new IllegalMonitorStateException();
Node first = firstWaiter;
if (first != null)
doSignal(first);
}
private void doSignal(Node first) {
do {
if ( (firstWaiter = first.nextWaiter) == null)
lastWaiter = null;
first.nextWaiter = null;
} while (!transferForSignal(first) &&
(first = firstWaiter) != null);
}
}
await和signal所做得时期其实很清楚,每个ConditionObject内部都有一个单独的队列,当一个线程因await而挂起时,它就会加入ConditionObject的队列中,signal则会把希望唤醒的线程重新加入AbstractQueuedSynchronizer的队列中去。
当调用await的时候addConditionWaiter和fullyRelease所做的事情分别是离开AbstractQueuedSynchronizer的队列和进入ConditionObject的队列。 而signal则会将这个结点从AbstractQueuedSynchronizer的队列带回ConditionObject的队列。
fullyRelease会返回在await前的重入深度,而acquireQueued会把这个场景再次恢复回去。 但是还有一个问题是await中的循环是做什么的,其实在acquireQueued中也有一段功能类似的循环:
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);
p.next = null; // help GC failed = false;
return interrupted;
}
if (shouldParkAfterFailedAcquire(p, node) &&
parkAndCheckInterrupt())
interrupted = true;
}
} finally {
if (failed)
cancelAcquire(node);
}
}
之所以要有这两个循环的存在,是因为LockSupport的park和unpark是公开的API,这两个循环的存在意义就是为了保证除了AbstractQueuedSynchronizer和ConditionObject之外不会再有其它的原因导致挂起的线程被唤醒。
那么题主所说的所谓“然后就一直循环进入await() 方法”是为了什么?
因为Condition一般是这样用的:
class Main {
private static Lock sLock = new ReentrantLock();
private static Condition sCondition = sLock.newCondition();
public static void main(String[] args) {
sLock.lock();
try {
while (...) {
sCondition.await();
}
// TODO } finally {
sLock.unlock();
}
}
}
这个逻辑类似于下面这一段:
class Main {
private static Object sMonitor = new Object();
public static void main(String[] args) {
synchronized (mMonitor) {
while (...) {
sMonitor.wait();
}
// TODO }
}
}
由于题主说自己只写了lock和await,于是我也试着调试了一下,发现不出所料地挂起了。
public class Main {
public static void main(String[] args) throws InterruptedException {
Lock lock = new ReentrantLock();
Condition condition = lock.newCondition();
lock.lock();
condition.await();
throw new AssertionError();
}
}
但是后来题主你更新了截图,我看了一下,我猜你是直接对着await调试的,这样是不对的,因为你构建项目用得是Gradle,Gradle也是个Java程序,它也要用到await,你图上的堆栈已经很明白了,这已经进到了Gradle的代码里面。
那么我就对着图上的堆栈给你讲一下吧,其实你自己也可以直接去看gradle的代码。
由于我做过基于gradle的android项目transform字节码插件,所以我的External Libraries中有gradle-api-6.3这个jar,我也就直接对着这个代码看了。
有兴趣的话可以看一看我的个人项目SweetChips。
首先,Gradle要有一个守护进程,这个daemon得这样启动:
package org.gradle.launcher.daemon.bootstrap;
public class GradleDaemon {
public static void main(String[] args) {
(new ProcessBootstrap()).run("org.gradle.launcher.daemon.bootstrap.DaemonMain", args);
}
}
然后就是一顿操作猛如虎,在org.gradle.launcher.bootstrap.ProcessBootstrap里面靠反射执行了org.gradle.launcher.daemon.bootstrap.DaemonMain的run。org.gradle.launcher.daemon.bootstrap.DaemonMain是org.gradle.launcher.bootstrap.EntryPoint的子类, 超类的run会调用子类的doAction。
顺着图上的堆栈咱们继续,doAction调用了org.gradle.launcher.daemon.server.Daemon的stopOnExpiration,然后是它的私有方法awaitExpiration,继续向下就是org.gradle.launcher.daemon.server.DaemonStateCoordinator的awaitStop,我把这个方法的代码贴在下面吧:
boolean awaitStop() {
this.lock.lock();
try {
while(true) {
try {
switch(this.state) {
case Idle:
case Busy:
LOGGER.debug("daemon is running. Sleeping until state changes.");
this.condition.await();
break;
case Canceled:
LOGGER.debug("cancel requested.");
this.cancelNow();
break;
case Broken:
throw new IllegalStateException("This daemon is in a broken state.");
case StopRequested:
LOGGER.debug("daemon stop has been requested. Sleeping until state changes.");
this.condition.await();
break;
case Stopped:
LOGGER.debug("daemon has stopped.");
boolean var1 = true;
return var1;
}
} catch (InterruptedException var5) {
throw UncheckedException.throwAsUncheckedException(var5);
}
}
} finally {
this.lock.unlock();
}
}
这和我上面给出的await用法示例简直完全符合!哦耶!与我的猜想相符。