AbstractQueuedSynchronizer 独占式源码阅读

概述

● 一个int成员变量 state 表示同步状态
● 通过内置的FIFO队列来完成资源获取线程的排队工作

属性

AbstractQueuedSynchronizer属性

   /*** 同步队列的头节点     */private transient volatile Node head;/*** 同步队列尾节点,enq 加入*/private transient volatile Node tail;/*** 同步状态*/private volatile int state;/*** 获取状态*/protected final int getState() {return state;}/*** 设置状态*/protected final void setState(int newState) {state = newState;}/*** CAS 设置状态*/protected final boolean compareAndSetState(int expect, int update) {// See below for intrinsics setup to support thisreturn unsafe.compareAndSwapInt(this, stateOffset, expect, update);}/*** The number of nanoseconds for which it is faster to spin* rather than to use timed park. A rough estimate suffices* to improve responsiveness with very short timeouts.*/static final long spinForTimeoutThreshold = 1000L;

Node 节点属性

 static final class Node {/** 共享节点 */static final Node SHARED = new Node();/** 独占节点 */static final Node EXCLUSIVE = null;// 在同步队列中等待的线程等待超时或被中断, 需要从同步队列中取消等待, 状态不会变化 |static final int CANCELLED = 1;// 后继节点处于等待状态, 当前节点释放了同步状态或者被取消, 通知后续节点, 使后续节点得以运行static final int SIGNAL = -1;// 值为-2, 节点在等待队列, 当其他线程 signal(),从等待队列中移除到同步队列中 |static final int CONDITION = -2;// 值为-3, 下一次共享获取同步状态将会无条件传播下去static final int PROPAGATE = -3;/*** 节点初始状态,初始化为0*/volatile int waitStatus;/*** 前一个节点*/volatile Node prev;/*** 后一个节点*/volatile Node next;/** 节点的线程*/volatile Thread thread;/*** 下一个等待者*/Node nextWaiter;/*** 是否是共享节点*/final boolean isShared() {return nextWaiter == SHARED;}/***  前一个节点*/final Node predecessor() throws NullPointerException {Node p = prev;if (p == null)throw new NullPointerException();elsereturn p;}Node() {    // Used to establish initial head or SHARED marker}Node(Thread thread, Node mode) {     // Used by addWaiterthis.nextWaiter = mode;this.thread = thread;}Node(Thread thread, int waitStatus) { // Used by Conditionthis.waitStatus = waitStatus;this.thread = thread;}}

常用方法

同步状态的三个方法:
● getState() 获取同步状态
● setState(int newState) 设置当前同步状态
● compareAndSetState(int expect, int update) CAS设置同步状态,原子操作

AbstractQueuedSynchronizer可重写的方法:

方法名称方法描述
boolean tryAcquire(int arg)独占式获取同步状态,查询当前状态是否符合预期,并且CAS设置
boolean tryRelease(int arg)独占式释放同步状态,释放后,等待获取同步状态的线程有机会获取同步状态
int tryAcquireShared(int arg)共享式获取同步状态,如果大于等于0,表示获取成功
boolean tryReleaseShared(int arg)共享式释放同步状态
boolean isHeldExclusively()在独占模式下被线程占用,表示是否被当前线程独占

AbstractQueuedSynchronizer提供的模版方法

方法名称方法描述
boolean acquire(int arg)独占式获取同步状态, 成功返回, 失败队列等待, 调用tryAcquire()
boolean acquireInterruptibly(int arg)acquire 相同, 但是可以中断
int tryAcquireNanos(int arg, long nanos)acquireInterruptibly 基础上增加了超时限制, 超时返回false, 返回true
acquireShared(int arg)共享式获取同步状态, 和acquire差不多, 区别是同一时刻可以有多个线程获取同步状态
acquireSharedInterruptibly(int arg)acquireShared 相同, 但是可以中断
int tryAcquireSharedInterruptibly(int arg, long nanos)acquireSharedInterrup

流程图

在这里插入图片描述

流程图主要方法源码阅读

acquire

独占式获取同步状态, 成功返回, 失败队列等待

public final void acquire(int arg) {// tryAcquire获取信号量// 如果失败 tryAcquire(arg)=false addWaiter入队列、acquireQueued 排队获取锁if (!tryAcquire(arg) &&acquireQueued(addWaiter(Node.EXCLUSIVE), arg))selfInterrupt();
}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 GCfailed = false;return interrupted;}// 前面节点设置为 singal,自己就可以睡眠了if (shouldParkAfterFailedAcquire(p, node) &&parkAndCheckInterrupt())// 被中断 尝试获取信号量interrupted = true;}} finally {if (failed)cancelAcquire(node);}
}

addWaiter

节点进入同步队列

    private Node addWaiter(Node mode) {// 创建节点Node node = new Node(Thread.currentThread(), mode);// Try the fast path of enq; backup to full enq on failureNode pred = tail;// 尾节点不为空if (pred != null) {// 设置当前节点的前一个节点为尾节点node.prev = pred;// cas 设置自己为尾节点if (compareAndSetTail(pred, node)) {pred.next = node;return node;}}// 尾节点为空 或 cas 设置自己为尾节点失败了enq(node);return node;}/*** 入队*/private Node enq(final Node node) {for (;;) {Node t = tail;// 尾节点为空,设置新的头节点if (t == null) { // Must initializeif (compareAndSetHead(new Node()))tail = head;} else {// 设置当前节点的前一个节点为尾节点node.prev = t;// cas 设置自己为尾节点if (compareAndSetTail(t, node)) {t.next = node;return t;}}}}

shouldParkAfterFailedAcquire

前面节点设置为 singal,设置成功返回true,失败false

 private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) {int ws = pred.waitStatus;// 前面的节点SIGNAL自己就可以park了if (ws == Node.SIGNAL)return true;if (ws > 0) {// 找到第一个不是取消状态的节点do {node.prev = pred = pred.prev;} while (pred.waitStatus > 0);pred.next = node;} else {/** 设置 WaitStatus SIGNAL*/compareAndSetWaitStatus(pred, ws, Node.SIGNAL);}return false;}

parkAndCheckInterrupt

   private final boolean parkAndCheckInterrupt() {LockSupport.park(this);return Thread.interrupted();}

acquireInterruptibly

acquire 相同, 但是可以中断

 public final void acquireInterruptibly(int arg)throws InterruptedException {// 被中断抛出InterruptedExceptionif (Thread.interrupted())throw new InterruptedException();if (!tryAcquire(arg))doAcquireInterruptibly(arg);}private void doAcquireInterruptibly(int arg)throws InterruptedException {final Node node = addWaiter(Node.EXCLUSIVE);boolean failed = true;try {for (;;) {final Node p = node.predecessor();if (p == head && tryAcquire(arg)) {setHead(node);p.next = null; // help GCfailed = false;return;}if (shouldParkAfterFailedAcquire(p, node) &&parkAndCheckInterrupt())// 被中断抛出InterruptedExceptionthrow new InterruptedException();}} finally {if (failed)cancelAcquire(node);}

tryAcquireNanos

acquireInterruptibly 基础上增加了超时限制, 超时返回false, 返回true

   public final boolean tryAcquireNanos(int arg, long nanosTimeout)throws InterruptedException {if (Thread.interrupted())throw new InterruptedException();return tryAcquire(arg) ||doAcquireNanos(arg, nanosTimeout);}private boolean doAcquireNanos(int arg, long nanosTimeout)throws InterruptedException {if (nanosTimeout <= 0L)return false;final long deadline = System.nanoTime() + nanosTimeout;final Node node = addWaiter(Node.EXCLUSIVE);boolean failed = true;try {for (;;) {final Node p = node.predecessor();if (p == head && tryAcquire(arg)) {setHead(node);p.next = null; // help GCfailed = false;return true;}nanosTimeout = deadline - System.nanoTime();// 超时返回falseif (nanosTimeout <= 0L)return false;if (shouldParkAfterFailedAcquire(p, node) &&nanosTimeout > spinForTimeoutThreshold)// park指定时间LockSupport.parkNanos(this, nanosTimeout);// 中断抛出异常if (Thread.interrupted())throw new InterruptedException();}} finally {if (failed)cancelAcquire(node);}}

release

释放信号量, 如果头节点不为空 状态为SINGAL, 唤醒头节点的下一个节点

public final boolean release(int arg) {if (tryRelease(arg)) {// 释放arg信号量成功Node h = head;// 如果头节点不为空 状态为SINGAL, 唤醒头节点的下一个节点if (h != null && h.waitStatus != 0)unparkSuccessor(h);return true;}return false;
}private void unparkSuccessor(Node node) {int ws = node.waitStatus;// 唤醒先修改waitStatus从SINGAL->0初始化if (ws < 0)compareAndSetWaitStatus(node, ws, 0);// 找到node之后第一个不被取消的节点, LockSupport.unpark唤醒该节点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);
}

参考文献

  • Java并发编程的艺术第二版 方腾飞、魏鹏、程晓明

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/765490.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【XR806开发板试用】使用PWM模块模拟手机呼吸灯提示功能

一般情况下&#xff0c;我们的手机在息屏状态&#xff0c;当收到消息处于未读状态时&#xff0c;会有呼吸灯提醒&#xff0c;这次有幸抽中XR806开发板的试用&#xff0c;经过九牛二虎之力终于将环境搞好了&#xff0c;中间遇到各种问题&#xff0c;在我的另一篇文章中已详细描述…

面试算法-82-不同路径

题目 一个机器人位于一个 m x n 网格的左上角 &#xff08;起始点在下图中标记为 “Start” &#xff09;。 机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角&#xff08;在下图中标记为 “Finish” &#xff09;。 问总共有多少条不同的路径&#xff1f; …

2403d,d语言直接利用llama.cpp

原文 无需绑定,只需制作个带单个包含的虚C文件,然后就可开始构建由llama.cpp提供支持的D应用,仅此而已,除了制作虚文件外,无需额外工作. 在窗口上使用dmdv2.107来测试. 代码 //llamad.c: #include "llama.h"从llama.cpp的简单的移植D版本示例: //llamad.d: modul…

MySQL (1)

目录 一、数据库的基本概念 1.1 数据 &#xff08;Data&#xff09; 1.2 表 1.3 数据库 2 数据库管理系统 3 数据库系统 二、数据库发展史 关于第三代数据库 三、关系型数据库 当今主流数据库介绍 关系数据库应用 四、非关系数据库介绍 五、MySQL数据库介绍 MySQL商业…

如何利用自动化和智能化技术提高仓储行业效率?

仓储行业作为物流领域的重要环节&#xff0c;其效率的提升对于整个供应链的顺畅运作至关重要。自动化和智能化技术的引入&#xff0c;为仓储行业带来了革命性的变革。 一&#xff0e;自动化技术的应用 自动化仓储系统 通过引入自动化仓储系统&#xff0c;如高架叉车、自动化…

vscode调试launch.json常用格式

目录 1、简单的模版 2、简单的案例 2.1、python 执行.py 文件 2.2、调式多个文件 2.3、torchrun、deepspeed 调试 1、简单的模版 定义一个简单的模版如下&#xff1a; {// 使用 IntelliSense 了解相关属性。 // 悬停以查看现有属性的描述。// 欲了解更多信息&#xff0c;请访…

redis和rabbitmq实现延时队列

redis和rabbitmq实现延时队列 延迟队列使用场景Redis中zset实现延时队列Rabbitmq实现延迟队列 延迟队列使用场景 1. 订单超时处理 延迟队列可以用于处理订单超时问题。当用户下单后&#xff0c;将订单信息放入延迟队列&#xff0c;并设置一定的超时时间。如果在超时时间内用户…

网络编程套接字——实现简单的TCP网络程序

目录 1、TCP socket API详解 socket()&#xff1a; bind()&#xff1a; listen(): accept(): connect(): 2、简易的TCP网络程序 TcpServer.hpp TcpClient.cc Main.cc Log.hpp ThreadPool.hpp Task.hpp Init.hpp Daemon.hpp dict.txt Makefile 1、TCP socket A…

CRM软件推荐2024:五款顶级产品解析,助您找到最佳选项!

一天之计在于晨&#xff0c;一年之计在于春。 2024年&#xff0c;民营经济发展继续壮大&#xff0c;这对于各行各业而言都是一种机遇挑战。企业想要规范化客户管理&#xff0c;实现销售增长&#xff0c;CRM软件仍然是一个不错的选择。在数字化时代&#xff0c;企业数字化转型已…

C语言运算符的优先级

C语言运算符的优先级 在C语言中&#xff0c;运算符的优先级决定了在复杂的表达式中先进行哪个运算&#xff0c;后进行哪个运算。优先级从高到低排列如下&#xff1a; 括号运算符&#xff1a;()、[]、->、.&#xff0c;它们的优先级最高&#xff0c;用于明确指定运算的先后…

基于SpringBoot实现WebSocket实时通讯的服务端和客户端

实现功能 服务端注册的客户端的列表&#xff1b;服务端向客户端发送广播消息&#xff1b;服务端向指定客户端发送消息&#xff1b;服务端向多个客户端发送消息&#xff1b;客户端给服务端发送消息&#xff1b; 效果&#xff1a; 环境 jdk&#xff1a;1.8 SpringBoot&#x…

Pytorch:nn.Upsample() 和nn.ConvTranspose2d()

nn.Upsample 原理 nn.Upsample 是一个在PyTorch中进行上采样&#xff08;增加数据维度&#xff09;的层&#xff0c;其通过指定的方法&#xff08;如nearest邻近插值或linear、bilinear、trilinear线性插值等&#xff09;来增大tensor的尺寸。这个层可以在二维或三维数据上按…

大模型+强化学习_通过强化学习对齐大模型和环境

英文名称: True Knowledge Comes from Practice: Aligning LLMs with Embodied Environments via Reinforcement Learning 中文名称: 实践出真知&#xff1a;通过强化学习将LLMS与具体环境对齐 链接: https://arxiv.org/abs/2401.14151 代码: https://github.com/WeihaoTan/TWO…

win10安装后 c盘 再分区

背景 500G的固态全用在C盘&#xff0c;现在发现分多了&#xff0c;想多出一个固态盘&#xff0c;这样方便其他文件读取更快 操作 点击开始菜单&#xff0c;搜索并打开“磁盘管理”。 在磁盘管理窗口中&#xff0c;找到你想要分区的硬盘&#xff08;通常是C盘&#xff09;&…

BI技巧丨个性化视觉对象

BOSS&#xff1a;那个&#xff0c;那个谁&#xff0c;最近用户反映了&#xff0c;说是你们做的报表不太行啊&#xff1f;&#xff01; 白茶&#xff1a;&#xff08;&#xff1f;&#xff1f;&#xff1f;&#xff09;老板&#xff0c;怎么说&#xff1f; BOSS&#xff1a;就是…

网络原理(5)——IP协议(网络层)

目录 一、IP协议报头介绍 1、4位版本 2、4位首部长度 3、8位服务器类型 4、16位总长度 5、16位标识位 6、3位标志位 7、13位偏移量 8、8位生存空间 9、8位协议 10、16位首部检验和 11、32位源IP地址 12、32位目的IP地址 二、IP协议如何管理地址&#xff1f; 1、动…

Redis入门到实战-第三弹

Redis入门到实战 Redis数据类型官网地址Redis概述Redis数据类型介绍更新计划 Redis数据类型 官网地址 声明: 由于操作系统, 版本更新等原因, 文章所列内容不一定100%复现, 还要以官方信息为准 https://redis.io/Redis概述 Redis是一个开源的&#xff08;采用BSD许可证&#…

《优化接口设计的思路》系列:第九篇—用好缓存,让你的接口速度飞起来

一、前言 大家好&#xff01;我是sum墨&#xff0c;一个一线的底层码农&#xff0c;平时喜欢研究和思考一些技术相关的问题并整理成文&#xff0c;限于本人水平&#xff0c;如果文章和代码有表述不当之处&#xff0c;还请不吝赐教。 作为一名从业已达六年的老码农&#xff0c…

2024Python计算机二级13

一维数据采用线性方式组织&#xff0c;集合不属于线性结构 程调度仅负责对CPU进行分配 快速排序每经过一次元素的交换会产生新的逆序 记住队列中为一个元素的情况 区分二叉树与完全二叉树&#xff0c;前序序列是先访问根节点再访问左子树和右子树&#xff0c;中序序列是访问左子…

《定时执行专家》:Nircmd 的超级搭档,解锁自动化新境界

目录 Nircmd 简介 《定时执行专家》与 Nircmd 的结合 示例&#xff1a; 自动清理电脑垃圾: 定时发送邮件: 定时关闭电脑: 《定时执行专家》的优势: 总结: 以下是一些其他使用示例&#xff1a; 立即下载《定时执行专家》&#xff1a; Nircmd 官方网站&#xff1a; 更…