news 2026/4/23 20:48:23

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

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
揭秘JUC:volatile与CAS,并发编程的两大基石

UC(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进行设置为1

if (compareAndSetState(0, acquires)) {

// 5 设置占用线程为当前线程并返回true

setExclusiveOwnerThread(current);

return true;

}

}

// 6 如果state不为0,并且当前线程等于锁占用的线程,则说明锁重入了。

else if (current == getExclusiveOwnerThread()) {

// 7 直接将state设置为+1

int 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为1

compareAndSwap(state, 1)

// 赋值操作,受volatile内存语义保护,防止重排序

x = 1;

// 释放锁,将state重置为0

state = 0;

// 唤醒其他等待线程

unpark(nonCurrentThread());

}

public void get() {

// 当前线程从主内存读取state值

while(state != 0) {

// 阻塞当前线程,等待锁释放

park(Thread.currentThread())

}

// CAS操作,尝试获取锁

compareAndSwap(state, 1)

// 读取共享变量x的最新值

int i = x;

// 其他操作...

// 释放锁,将state重置为0

state = 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并发包中高层类的实现,构建了一个层次分明、功能强大的并发编程框架。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/23 14:48:22

数据结构总结笔记

1 数据结构三要素是什么&#xff1f;逻辑结构包括什么&#xff1f;存储结构包括什么&#xff1f; 数据结构三要素&#xff1a;逻辑结构、存储结构、数据运算。 逻辑结构包括线性结构和非线性结构&#xff1a; 线性结构&#xff1a;线性表、栈、队列&#xff1b;非线性结构&a…

作者头像 李华
网站建设 2026/4/23 17:32:31

PHP 开发者必须掌握的基本 Linux 命令

开始 PHP 开发时&#xff0c;我并没有特别的理由选择 Linux。既不是出于对开源软件的热情&#xff0c;也不是认为 Linux 比 macOS 或 Windows 更优秀。当时只是希望找到一个更轻量、更可定制的开发环境。对我而言&#xff0c;Linux 就是一个可能提升编码效率的工具。随着项目规…

作者头像 李华
网站建设 2026/4/23 13:13:54

用格子玻尔兹曼方法(LBM)模拟不可压缩密度守恒压力驱动流

格子玻尔兹曼方法&#xff08;LBM&#xff09;模拟不可压缩密度守恒压力驱动流&#xff0c;MATLAB代码嘿&#xff0c;大家好&#xff01;今天来聊聊如何使用格子玻尔兹曼方法&#xff08;LBM&#xff09;模拟不可压缩密度守恒压力驱动流&#xff0c;并且会用MATLAB代码来实现。…

作者头像 李华
网站建设 2026/4/23 13:39:49

基于LQR控制算法的四轮独立电驱动汽车横向稳定性控制研究

适用方向&#xff1a;基于LQR控制算法的直接横摆力矩控制&#xff08;DYC&#xff09;的四轮独立电驱动汽车的横向稳定性控制研究 主要内容&#xff1a;利用carsim建模&#xff0c;在simulink中搭建控制器&#xff0c;然后进行联合。 实现汽车在高速低附着路面下完成双移线工况…

作者头像 李华
网站建设 2026/4/23 13:39:56

IPv6违规外联防御指南:从风险盲区到可管可控

在数字化转型加速推进的今天&#xff0c;IPv6作为下一代互联网协议&#xff0c;正以其庞大的地址空间和高效的通信机制&#xff0c;推动着网络基础设施的全面升级。根据APNIC监测数据&#xff0c;2022年全球IPv6支持能力持续增强&#xff0c;支持率从2021年3月的28.31%显著提升…

作者头像 李华
网站建设 2026/4/23 13:14:48

网型逆变器小干扰稳定性分析与控制策略优化:Simulink仿真探索

跟网型逆变器小干扰稳定性分析与控制策略优化simulink仿真模型和代码 现代逆变技术 阻抗重塑 双锁相环 可附赠参考文献&#xff08;英文&#xff09; 和一份与模型完全对应的中文版报告在现代逆变技术的领域中&#xff0c;网型逆变器的小干扰稳定性分析以及控制策略的优化是至关…

作者头像 李华