
java多线程编程之volatile和CAS
独立操作:操作对结果没有依赖,或者变量的状态不影响其他变量。 不需要强一致性:可以允许读取到稍微过期的数据。 比较当前值(OldValue)和预期值。 交换当前值:只有当前值等于OldValue时,才将其修改为NewValue。 性能瓶颈:当传统锁机制成为性能瓶颈时,例如在高并发场景下。 高效率操作:在需要频繁读写且不依赖当前值的情况下。 开发需求:当对传统锁的阻塞性寻求改进时。
发布日期:2021-05-10 05:11:20
浏览次数:27
分类:精选文章
本文共 2904 字,大约阅读时间需要 9 分钟。
Java多线程中的Volatile与CAS机制解析
一、Volatile机制
原理
在Java中,Volatile是用于确保共享变量在多线程环境下能够保持可见性和一致性。但与传统的锁机制相比,Volatile更偏向于单纯的可见性保证,而不是强一致性。Volatile通过以下机制实现可见性:
缓存一致性协议
Javaμμεื่ง通过缓存一致性协议(Cache Coherency)来维护多线程之间的数据一致性。当一个CPU进行数据写操作时,会通过缓存一致性协议通知其他CPU,更新它们的缓存内容。这确保了其他线程能够及时获取到最新的数据值。总线锁与缓存锁
操作系统通过两种锁机制来实现Volatile的可见性:- 总线锁:锁定整个总线,只允许一个CPU进行操作。
- 缓存锁:只锁定相关的缓存行,提高锁的粒度并减少性能消耗。
限制
尽管Volatile保证了可见性,但它并不具备原子性:
- 非原子性:像
x++
这样的操作其实是一个两步扩展操作,不能保证原子性。因此,在高并发环境下可能导致“丢失更新”问题。 - 脏数据问题:在多核环境下,若一个CPU修改了主内存数据,其他CPU可能会继续读取旧缓存内容,导致计算错误。
使用场景
示例
// 示例代码:两个线程同时读写同一变量xstatic volatile Integer x = 0;public class VolatileExample { public static void main(String[] args) { ExecutorService service = Executors.newCachedThreadPool(); service.execute(new Runnable() { @Override public void run() { for (int i = 0; i < 1000; i++) { x++; System.out.println("Thread 1: value=" + x); } } }); service.execute(new Runnable() { @Override public void run() { for (int i = 0; i < 1000; i++) { x++; System.out.println("Thread 2: value=" + x); } } }); service.shutdown(); }}
注意:在上述示例中,由于x++
操作的非原子性,实际结果可能小于预期值。
二、CAS机制
含义
CAS(Compare And Swap)是一种乐观锁机制,通过以下步骤实现原子性操作:
实现原理
- JVM层面:通过
compareAndSwap()
方法调用C层的原子操作实现,在HotSpot JVM中,这样实现的CAS操作具有高效率。 - OS层面:通过总线锁和缓存锁策略确保原子性:
- 总线锁在多核环境下减少数据不一致性问题。
- 缓存锁利用缓存一致性协议,减少锁的粒度。
优点
- 高效:通过硬件指令实现,效率接近单核性能。
- 粒度细:可以应用在优化I/O操作等场景。
- 非阻塞:能够减少同步开销,适用于高并发环境。
###局限性
ABA问题
- 若CPU1先将值从A改为B,CPU2再将B改为A,而在CPU1中按旧值A判断,依然会认为值未发生改变。 AtomicStampedReference通过增加版本号解决这一问题。
自旋问题
- CAS操作可能导致线程进行多次自旋,影响性能。
复杂性
- CAS操作逻辑复杂,导致代码比传统锁更难维护。
示例
static AtomicInteger x = new AtomicInteger();public class AtomicIntegerExample { public static void main(String[] args) { ExecutorService service = Executors.newCachedThreadPool(); service.execute(new Runnable() { @Override public void run() { for (int i = 0; i < 1000; i++) { x.incrementAndGet(); System.out.println("Thread 1: value=" + x.get()); } } }); service.execute(new Runnable() { @Override public void run() { for (int i = 0; i < 1000; i++) { x.incrementAndGet(); System.out.println("Thread 2: value=" + x.get()); } } }); service.shutdown(); }}
三、什么时候使用CAS+Volatile?
总结
Java中的Volatile和CAS机制为多线程编程提供了更高效的共享资源访问策略。Volatile通过缓存一致性协议保证可见性,而CAS通过乐观锁机制实现原子性操作。在高并发环境下,合理结合两者可以显著提升系统性能。然而,两者的使用需要谨慎考虑具体场景,避免非原子性和ABA问题带来的潜在风险。
发表评论
最新留言
能坚持,总会有不一样的收获!
[***.219.124.196]2025年05月08日 11时00分56秒
关于作者

喝酒易醉,品茶养心,人生如梦,品茶悟道,何以解忧?唯有杜康!
-- 愿君每日到此一游!
推荐文章
Android控件之ProgressBar
2019-03-15
Activity之间传递数据的三种方式详解
2019-03-15
Kafka入门(常见错误)
2019-03-15
HttpServletResponse-完成文件下载
2019-03-15
什么题目的暂时还没想好
2019-03-15
Python中pip安装模块太慢
2019-03-15
docker安装
2019-03-15
N皇后问题解法(递归+回朔)
2019-03-15
面试题 08.01. 三步问题
2019-03-15
剑指 Offer 11. 旋转数组的最小数字
2019-03-15
剑指 Offer 57. 和为s的两个数字
2019-03-15
git 在本地删除、添加远端的源
2019-03-15
字符串的反转
2019-03-15
docker用法
2019-03-15
word文档注入(追踪word文档)未完
2019-03-15
作为我的第一篇csdn博客吧
2019-03-15
Linux Ubuntu 用命令安装MySql
2019-03-15
java中简单实现栈
2019-03-15
ajax异步提交失败
2019-03-15