java lock park_Java中condition的LockSupport.park(this)是怎么工作的?

有一说一,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用法示例简直完全符合!哦耶!与我的猜想相符。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值