深入理解 JUC:AQS 队列同步器(11)
< 0 // 此时 h 是之前的头结点|| (h = head) == null || h.waitStatus < 0) { // 此时 h 已经更新为当前头结点Node s = node.next;// 如果后继结点以共享模式在等待 , 或者后继结点未知 , 则尝试唤醒后继结点if (s == null || s.isShared()) {this.doReleaseShared();}}}因为当前结点已经获取到资源 , 所以需要将当前结点记录到头结点中 。 此外 , 如果满足以下 2 种情况之一 , 还需要唤醒后继结点:
- 参数 propagate > 0 , 即存在可用的剩余资源;
- 前任头结点或当前头结点不存在 , 或指明后继结点需要被唤醒 。
共享释放资源针对共享模式释放资源 , AbstractQueuedSynchronizer 同样定义了单一实现 , 即 AbstractQueuedSynchronizer#releaseShared 方法 , 该方法本质上也是一个调度的过程 , 具体释放资源的操作交由 tryReleaseShared 方法完成 , 由子类实现 。 方法 AbstractQueuedSynchronizer#releaseShared 实现如下:
public final boolean releaseShared(int arg) {// 尝试释放资源if (this.tryReleaseShared(arg)) {// 释放资源成功 , 唤醒后继结点this.doReleaseShared();return true;}return false;}private void doReleaseShared() {/** Ensure that a release propagates, even if there are other in-progress acquires/releases.* This proceeds in the usual way of trying to unparkSuccessor of head if it needs signal.* But if it does not, status is set to PROPAGATE to ensure that upon release, propagation continues.* Additionally, we must loop in case a new node is added while we are doing this.* Also, unlike other uses of unparkSuccessor, we need to know if CAS to reset status fails, if so rechecking.*/for (; ; ) {Node h = head;if (h != null// 如果头结点状态为 SIGNAL , 则在唤醒后继结点之前尝试清除当前结点的状态if (ws == Node.SIGNAL) {if (!compareAndSetWaitStatus(h, Node.SIGNAL, 0)) {// loop to recheck casescontinue;}// 唤醒后继结点this.unparkSuccessor(h);}/** 如果后继结点暂时不需要被唤醒 , 则基于 CAS 尝试将目标结点的 waitStatus 由 0 修改为 PROPAGATE ,* 以保证后续由唤醒通知到来时 , 能够将通知传递下去*/else if (ws == 0}}// 如果头结点未变更 , 则说明期间持有锁的线程未发生变化 , 能够走到这一步说明前面的操作已经成功完成if (h == head) {break;}// 如果头结点发生变更 , 则说明期间持有锁的线程发生了变化 , 需要重试以保证唤醒动作的成功执行}}
如果释放资源成功 , 需要依据头结点当下等待状态分别处理:- 如果头结点的等待状态为 SIGNAL , 则表明后继结点需要被唤醒 , 在执行唤醒操作之前需要清除等待状态 。
- 如果头结点状态为 0 , 则表示后继结点不需要被唤醒 , 此时需要将结点状态修改为 PROPAGATE , 以保证后续接收到唤醒通知时能够将通知传递下去 。
【深入理解 JUC:AQS 队列同步器】从下一篇开始 , 我们将介绍 JUC 中基于 AQS 实现的组件 , 包括 ReentrantLock、ReentrantReadWriteLock、CountDownLatch , 以及 Semaphore 等 , 去分析 AQS 中定义的模板方法是如何在这些组件中进行实现的 。
推荐阅读
- 全新8核国产CPU深入探秘:马上能买到
- 数据|新基建时代,高大全的数据管理解决方案是怎样“炼”成的?
- 16G运存+256G内存,专业骁龙865旗舰,性价比深入人心
- 深入理解Netty编解码、粘包拆包、心跳机制
- 绿色骑行深入校园,共享单车长途长时需求量提升
- 不被理解的超时代发明,你知道几个?在线膜拜大神,西瓜视频真相
- 深入调查SolarWinds黑客事件 微软已查封一个核心服务器
- 《深入理解Java虚拟机》:Java内存区域
- 深入探讨 JavaScript 逻辑赋值运算符
- 彻底理解 IO 多路复用实现机制