jdk源码解读-并发包-Lock-ReentrantLock(2)--await()与signal()方法走读
来源:互联网 发布:乐高编程机器人难不难 编辑:程序博客网 时间:2024/06/18 00:51
本人知乎技术文章
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. * * <p>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}. * * <p>This class is Serializable, but all fields are transient, * so deserialized conditions have no waiters. */public class ConditionObject implements Condition, java.io.Serializable {
因为线程是先通过lock()获得锁资源,然后调用await()时,先释放锁资源然后park。所以park前要先释放锁,让别的线程获得争取锁资源的权利。
调用流程图:
1.await()
/** * Implements interruptible condition wait. * <ol> * <li> If current thread is interrupted, throw InterruptedException. * <li> Save lock state returned by {@link #getState}. * <li> Invoke {@link #release} with saved state as argument, * throwing IllegalMonitorStateException if it fails. * <li> Block until signalled or interrupted. * <li> Reacquire by invoking specialized version of * {@link #acquire} with saved state as argument. * <li> If interrupted while blocked in step 4, throw InterruptedException. * </ol> */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);
}
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 当前线程,这时这个线程又获得了竞争锁资源的资格。
- jdk源码解读-并发包-Lock-ReentrantLock(2)--await()与signal()方法走读
- jdk源码解读-并发包-Lock-ReentrantLock(1)--lock()与unlock()方法走读
- JDK源码走读之ReentrantLock
- jdk并发包ReentrantLock 源码导读
- jdk源码解读-并发包-Lock-ReentrantReadWriteLock(1)-整体介绍以及读锁的lock 和 unlock 解析
- JDK并发包---(2)重入锁ReentrantLock:中断响应
- 线程同步ReentrantLock,condition(await,signal)
- java并发包-ReentrantLock(一):lock()是如何工作的
- ReentrantLock解析,lock与unlock方法分析
- await/signal/lock实现生产消费者模式
- JDK并发包---(1)重入锁ReentrantLock:基本使用
- JDK并发包---(3)重入锁ReentrantLock:锁申请等待限时
- JDK并发包---(5)重入锁ReentrantLock:公平锁
- JDK并发包---(6)重入锁ReentrantLock搭档:Condition条件
- 码农小汪-ReentrantLock-lock方法
- java 线程 Lock 锁使用Condition实现线程的等待(await)与通知(signal)
- join(),ReentrantLock结合Condition的await(),signal()的使用
- Lock与ReentrantLock
- 常用Java设计模式系列(3)- 代理模式
- 1032: 百钱百鸡问题
- 开启 Chrome 的日志
- 图说2016深度学习十大指数级增长
- log4j自定义分级过滤日志
- jdk源码解读-并发包-Lock-ReentrantLock(2)--await()与signal()方法走读
- 怀念WAP网站和让IE浏览器支持WAP网站
- Android 自定义控件属性
- 卡尔曼滤波
- HBase表导出到hdfs
- 新手上路,请多多指教
- SDUT 3254 Stars【二维前缀和+二分+暴力枚举】
- django关于websocket的资料
- Android Span 的使用