揭秘JUC:volatile与CAS,并发编程的两大基石

news/2025/9/27 11:32:04/文章来源:https://www.cnblogs.com/poemyang/p/19114881

揭秘JUC:volatile与CAS,并发编程的两大基石

JUC(java.util.concurrent)并发包,作为Java语言并发编程的利器,由并发编程领域的泰斗道格·利(Doug Lea)精心打造。它提供了一系列高效、线程安全的工具类、接口及原子类,极大地简化了并发编程的开发流程与管理复杂度。

JUC并发包与happens-before、内存语义的关系

image

探索JUC并发包,会发现它与Java内存模型中的happens-before原则及内存语义紧密相连。从高层视角俯瞰,volatile关键字与CAS(Compare-And-Swap)操作构成了JUC并发包底层实现的核心基石。接下来,以并发工具Lock为例,剖析其背后的实现机制。

class LockExample {int x = 0;Lock lock = new ReentrantLock();public void set() {// 获取锁lock.lock();       try {x = 1;} finally {// 释放锁lock.unlock();  }}public void get() {// 获取锁lock.lock();        try {int i = x;// ......} finally {// 释放锁lock.unlock();   }}
}

Lock的实现依赖于Java同步器框架(AbstractQueuedSynchronizer,AQS)。AQS内部维护了一个由volatile修饰的整型变量state,用于表示同步状态。
‌ 1)获取锁‌:当调用Lock的lock()方法时,会触发AQS的tryAcquire()方法尝试获取锁。该方法首先检查当前state是否为0(表示锁未被占用),若是,则通过CAS操作将state设置为1,并标记当前线程为锁的持有者。若锁已被当前线程持有(即重入锁情况),则直接增加state的值。
‌ 2)释放锁‌:当调用Lock的unlock()方法时,会触发AQS的tryRelease()方法释放锁。该方法首先减少state的值,若减少后state为0,则表示锁已完全释放,同时清除锁的持有者信息。

// 关键volatile变量
private volatile int state;protected final boolean tryAcquire(int acquires) {// 1 获取到当前线程final Thread current = Thread.currentThread();// 2 获取到当前锁的state值int c = getState();// 3 如果state值为0,则是无线程占用锁if (c == 0) {// 4 compareAndSetState则通过CAS对state进行设置为1if (compareAndSetState(0, acquires)) {// 5 设置占用线程为当前线程并返回truesetExclusiveOwnerThread(current);return true;}}// 6 如果state不为0,并且当前线程等于锁占用的线程,则说明锁重入了。else if (current == getExclusiveOwnerThread()) {// 7 直接将state设置为+1int nextc = c + acquires;if (nextc < 0)throw new Error("Maximum lock count exceeded");setState(nextc);return true;}// 8 如果是false,则说明是其他线程,直接返回false。return false;
}protected final boolean tryRelease(int releases) {// 1 对state进行减值int c = getState() - releases;// 2 判断当前线程等于锁占用的线程if (Thread.currentThread() != getExclusiveOwnerThread())throw new IllegalMonitorStateException();boolean free = false;// 3 当c值为0,代表释放锁成功if (c == 0) {free = true;// 4 设置为当前锁没有线程独占setExclusiveOwnerThread(null);}// 5 将state重新置为0,意味其他线程可以重新抢锁setState(c);// 6 释放锁成功return free;
}

从上述代码中,可以观察到volatile变量state在锁获取与释放过程中的关键作用。根据volatile的happens-before规则,释放锁的线程在修改volatile变量之前对共享变量的修改,对于后续获取该锁的线程来说是可见的。这确保了锁机制的正确性与线程间的数据一致性。
为了更直观地理解Lock的获取与释放过程,我们可以将其简化为如下伪代码。

class SimplifiedLockExample {int x = 0;volatile int state;public void set() {// 当前线程从主内存读取state值while(state != 0) {// 伪代码 阻塞当前线程park(Thread.currentThread())} // CAS操作,确保只有一个线程能成功设置state为1compareAndSwap(state, 1)// 赋值操作,受volatile内存语义保护,防止重排序x = 1;// 释放锁,将state重置为0state = 0;  // 唤醒其他等待线程unpark(nonCurrentThread());}public void get() {// 当前线程从主内存读取state值while(state != 0) {// 阻塞当前线程,等待锁释放park(Thread.currentThread())}          // CAS操作,尝试获取锁 compareAndSwap(state, 1)// 读取共享变量x的最新值int i = x;// 其他操作...// 释放锁,将state重置为0state = 0;// 唤醒其他等待线程unpark(nonCurrentThread());   }// 伪代码方法,实际实现需依赖底层系统调用private void park(Thread thread) private void unpark(Thread thread) private boolean compareAndSwap(int expect, int newValue, int updateValue) private Thread nonCurrentThread()
}

Java的CAS会使用现代处理器上提供的原子指令,实现无锁的线程安全更新机制。同时,volatile变量的读/写可以实现线程线程之间的通信。如果仔细分析JUC并发包的源代码实现,会发现一个通用化的实现模式。
‌ 1)声明共享变量为volatile‌:确保变量的可见性与有序性。
‌ 2)使用CAS的原子条件更新‌:实现线程间的同步与数据的一致性更新。
‌ 3)配合volatile的读/写内存语义‌:实现线程间的通信与数据传递。
这一模式在AQS、非阻塞数据结构(如ConcurrentHashMap)及原子变量类(如AtomicInteger)等JUC并发包的基础类中得到了广泛应用。而这些基础类又进一步支撑了JUC并发包中高层类的实现,构建了一个层次分明、功能强大的并发编程框架。

未完待续

很高兴与你相遇!如果你喜欢本文内容,记得关注哦

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

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

相关文章

题解:P11667 [USACO25JAN] Astral Superposition B

题解:P11667 [USACO25JAN] Astral Superposition B 发一篇之前在luogu上没发出去的题解(考USACO时的考场思路+代码) 题意理解每颗星星要么消失,要么向右移动 A 像素,并且向下移动 B 像素 (0≤A,B≤N)也就是行(…

【项目实战 Day7】springboot + vue 苍穹外卖架构(微信小程序 + 微信登录模块 完结)

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …

深入解析:Pytorch框架笔记

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …

网站建设服务标准ui网页界面设计素材

文章目录 一、stack的使用1.stack的介绍2.stack的使用 二、queue的使用1.queue的护额晒2.queue的使用 三、stack和queue相关算法题1.最小栈2.栈的压入、弹出序列3.逆波兰表达式4.两个栈实现一个队列5.用两个队列实现栈6.二叉树的层序遍历1.双队列2.用一个变量levelSize去控制 7…

北极通讯网络题解(做题记录)

北极通讯网络题解(做题记录) 前言 本文以一道 Kruskal 的好题实例来讲一下 Kruskal 的过程,对于初学 Kruskal 的OIer们有很大的帮助。 luogu 相似题:P1991 无线通讯网。 题目简述 有 n 座村庄,每座村庄的坐标用一对…

如何在局域网中做网站wordpress怎样发布时间

SpringMVC 的入门 1环境搭建 1.1.创建工程 1.2.添加web支持 右键项目选择Add framework support... 2.添加web支持 ​ 3.效果 注意&#xff1a; 不要先添加打包方式将web目录要拖拽到main目录下&#xff0c;并改名为webapp 1.3.pom.xml <?xml version"1.0&q…

elasticsearch安装插件 - 实践

elasticsearch安装插件 - 实践pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco"…

个人学习——前端react项目框架

文件作用 package.json npm脚本部分"scripts" 项目启动与打包"dev": "vite" 启动 开发环境,开启本地服务器,支持热更新。 用法:npm run dev "build": "tsc &&…

软件基础第一次作业

这个作业属于哪个课程 https://edu.cnblogs.com/campus/zjlg/25rjjc这个作业的目标 对自我进行分析和评估,了解博客使用方法,说明对课程的想法姓名-学号 林子渊 2023333503079自我介绍: 我叫林子渊,来自 23 自动化…

网站建设7个基本流程分析统一门户登录

一、简述 这里的代码主要是基于图像的推荐系统,该系统利用 ResNet-50 深度学习模型作为特征提取器,并采用余弦相似度来查找给定输入图像的最相似嵌入。 该系统旨在根据所提供图像的视觉内容为用户提供个性化推荐。 二、所需环境 Python 3.x tensorflow ==2.5.0 numpy==1.21.…

.net商城网站模板下载宁乡电商网站建设收费

title: URL编码&#xff1a;原理、应用与安全性 date: 2024/3/29 18:32:42 updated: 2024/3/29 18:32:42 tags: URL编码百分号编码特殊字符处理网络安全应用场景标准演变未来发展 在网络世界中&#xff0c;URL&#xff08;统一资源定位符&#xff09;是我们访问网页、发送请求…

LGP9755 [CSP-S 2023] 种树 学习笔记

LGP9755 [CSP-S 2023] 种树 学习笔记 Luogu Link 前言 故地重游。 巧合的是,上次写这道题刚好是在去年的九月二十七日,整整一年前。 题意简述 给定一个 \(n\) 个点,\(n-1\) 条边的简单无向连通图。好吧,这片地本身…

7、revision 是 Maven 3.5+ 引入的现代版本管理机制 - 实践

7、revision 是 Maven 3.5+ 引入的现代版本管理机制 - 实践pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consol…

P1731 生日蛋糕 做题记录

洛谷P1731 生日蛋糕 做题记录 题意简述 一个生日蛋糕由几个圆柱体组成,每个圆柱体的底面半径和高从下到上严格递减,现给出蛋糕的体积 N pi 以及层数 M,试求蛋糕的最小表面积。 思路速通 基本为 DFS ,对于每层的半径…

详细介绍:【MySQL】MySQL数据库入门指南

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …

如何有效提升代码覆盖率:从单元测试到集成测试的实践指南

Go语言代码覆盖率实现 一、什么是代码覆盖率代码覆盖率是软件测试中的一种白盒测试度量指标,表示程序源代码中被执行的比例。简单来说,就是“我的测试到底跑过多少代码”。 覆盖率常见的几种标准:语句覆盖(段覆盖、…

深入解析:SSM网络游戏交易系统a9n72(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面

深入解析:SSM网络游戏交易系统a9n72(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto …

Spring知识点(2)

一、有哪些依赖注入方式?构造方法注入:通过调用类的构造方法,推荐用于强依赖(没有依赖对象就没法工作)。这也是官方推荐的注入方式。好处:依赖不可变(final修饰)、更安全。@Component public class UserServic…

成都电子商务网站建设非寻服饰网站建设规划书

文章目录 “预训练微调大模型”的模式以提示/指令模式直接使用大模型“预训练微调大模型”模式和Prompt/Instruct模式的异同小结 “预训练微调大模型”的模式 经过预训练的大模型所习得的语义信息和所蕴含的语言知识&#xff0c;很容易向下游任务迁移。NLP应用人员可以根据自己…

超越实习期的AI自动化工具:播客工作流与Slack导出器实战

本文详细介绍实习期间基于Claude AI模型开发的两个自动化工具:播客工作流年省1250小时人工,Slack导出器实现智能知识检索。包含技术架构、问题解决方案和实际应用效果,展现AI如何增强企业工作效率。超越实习期的实习…