java lock await_jdk源码解读-并发包-Lock-ReentrantLock(2)--await()与signal()方法走读

ReentrantLock 的基本操作除了lock()和unlock()外,还有condition的await()和signal()。但是是通过调用AbstractQueuedSynchronizer的内部类CondtionObject来实现的。所以await()和singnal()的操作主要在CondtionObject类里。

如上图可以看到,ConditonObject是AbstractQueuedSynchronizer的内部类,同时上节讲解lock()和unlock()提到的Node也是它的内部类,以及其他方法组成了依赖FIFO waiting queue的阻塞锁和相关同步器(semaphores,events,等待)基本框架。

现在主要看一下内部类ConditionObject:

/*** Condition implementation for a {@link* AbstractQueuedSynchronizer} serving as the basis of a {@link* Lock} implementation.**

Method documentation for this class describes mechanics,* not behavioral specifications from the point of view of Lock* and Condition users. Exported versions of this class will in* general need to be accompanied by documentation describing* condition semantics that rely on those of the associated* {@code AbstractQueuedSynchronizer}.**

This class is Serializable, but all fields are transient,* so deserialized conditions have no waiters.*/

public class ConditionObject implements Condition, java.io.Serializable {一. await操作的流程:

因为线程是先通过lock()获得锁资源,然后调用await()时,先释放锁资源然后park。所以park前要先释放锁,让别的线程获得争取锁资源的权利。

调用流程图:

1.await()

/*** Implements interruptible condition wait.*

  1. *
  2. If current thread is interrupted, throw InterruptedException.*
  3. Save lock state returned by {@link #getState}.*
  4. Invoke {@link #release} with saved state as argument,* throwing IllegalMonitorStateException if it fails.*
  5. Block until signalled or interrupted.*
  6. Reacquire by invoking specialized version of* {@link #acquire} with saved state as argument.*
  7. If interrupted while blocked in step 4, throw InterruptedException.*
*/

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);

}

首先用addConditionWaiter()方法把这个线程包装成Node并放入condition queue。

2.addConditionWaiter():加入condition等待队列。

/*** Adds a new waiter to wait queue.* @return its new wait node*/

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队列中没有被cancel的lastWaiter,然后把当前Node设为lastWaiter。

3.fullyRelease(node):释放当前state值。并返回释放前的值。

/*** Invokes release with current state value; returns saved state.* Cancels node and throws exception on failure.* @param node the condition node for this wait* @return previous sync state*/

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;

}

}

4.release(savedState):tryRelease(arg)调用释放锁资源:

/*** Releases in exclusive mode. Implemented by unblocking one or* more threads if {@link #tryRelease} returns true.* This method can be used to implement method {@link Lock#unlock}.** @param arg the release argument. This value is conveyed to* {@link #tryRelease} but is otherwise uninterpreted and* can represent anything you like.* @return the value returned from {@link #tryRelease}*/

public final boolean release(int arg) {

if (tryRelease(arg)) {

Node h = head;

if (h != null && h.waitStatus != 0)

unparkSuccessor(h);

return true;

}

return false;

}

5.unparkSuccessor(h):叫醒syn queue中沉睡的线程:找到头结点后第一个没有被cancel的节点,然后对这个节点包装的线程执行unpark()操作

/*** Wakes up node's successor, if one exists.** @param node the node*/

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);

}

await()操作总结:

1.新建包装当前线程的node放到condition waiting queue中去。

2.释放此节点的锁资源。

3.找到syn queue中头节点后第一个没被cancel的节点并叫醒这个节点沉睡的线程。

4.对当前线程进行park();

二. signal():首先这个线程获取到了锁资源,然后执行signal()操作,把condition queue 中的第一个节点删除,并把这个节点放入syn queue 。

调用图:

1.signal():

/**

* Moves the longest-waiting thread, if one exists, from the

* wait queue for this condition to the wait queue for the

* owning lock.

*

* @throws IllegalMonitorStateException if {@link #isHeldExclusively}

* returns {@code false}

*/

public final void signal() {

if (!isHeldExclusively())

throw new IllegalMonitorStateException();

Node first = firstWaiter;

if (first != null)

doSignal(first);

}对condition queue 第一个节点进行唤醒。

2.doSignal(first):从队头找,找到第一个非空节点进行节点迁移。

/**

* Removes and transfers nodes until hit non-cancelled one or

* null. Split out from signal in part to encourage compilers

* to inline the case of no waiters.

* @param first (non-null) the first node on condition queue

*/

private void doSignal(Node first) {

do {

if ( (firstWaiter = first.nextWaiter) == null)

lastWaiter = null;

first.nextWaiter = null;

} while (!transferForSignal(first) &&

(first = firstWaiter) != null);

}

3.transferForSignal(Node node):把当前节点从condition queue 迁移到sync queue 中。

final boolean transferForSignal(Node node) {

if (!compareAndSetWaitStatus(node, Node.CONDITION, 0))

return false;

Node p = enq(node);

int ws = p.waitStatus;

if (ws > 0 || !compareAndSetWaitStatus(p, ws, Node.SIGNAL))

LockSupport.unpark(node.thread);

return true;

}

先调用enq(node);把节点放到sync queue 的队尾,同时unpark 当前线程,这时这个线程又获得了竞争锁资源的资格。

Aa

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值