news 2026/6/9 19:17:43

Java中为什么volatile不能解决多写问题?

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Java中为什么volatile不能解决多写问题?

上述规约是一个关于Java并发编程的重要问题。本篇博文我来详细解释一下:

1.volatile的内存可见性

volatile的作用:

  • 保证可见性:当一个线程修改了volatile变量的值,新值会立即刷新到主内存,其他线程读取时会从主内存重新获取最新值
  • 禁止指令重排序:防止JVM的指令重排序优化

示例:

publicclassVolatileExample{privatevolatilebooleanflag=false;publicvoidwriter(){flag=true;// 写操作}publicvoidreader(){if(flag){// 读操作// 一定能看到最新值}}}

2.为什么volatile不能解决多写问题

publicclassCounter{privatevolatileintcount=0;// 多线程调用会有问题publicvoidincrement(){count++;// 不是原子操作:读→改→写}}

问题分析

线程A:读取count=0 线程B:读取count=0 线程A:count+1=1,写回 线程B:count+1=1,写回 // 结果应该是2,实际是1

3.解决方案对比

方案1:AtomicInteger

importjava.util.concurrent.atomic.AtomicInteger;publicclassAtomicExample{privateAtomicIntegercount=newAtomicInteger(0);publicvoidincrement(){count.incrementAndGet();// 原子操作}publicintget(){returncount.get();}}

原理:基于CAS(Compare And Swap)

publicfinalintincrementAndGet(){returnunsafe.getAndAddInt(this,valueOffset,1)+1;}// 实际是自旋CAS操作

方案2:LongAdder(JDK8+推荐)

importjava.util.concurrent.atomic.LongAdder;publicclassLongAdderExample{privateLongAddercount=newLongAdder();publicvoidincrement(){count.increment();// 性能更好}publiclongsum(){returncount.sum();}}

4.性能对比分析

特性AtomicLongLongAdder
原理CAS自旋分段CAS
高并发写性能一般优秀
读性能O(1)O(N)需要合并
内存占用较高
适用场景读写均衡写多读少

5.完整示例

importjava.util.concurrent.atomic.AtomicInteger;importjava.util.concurrent.atomic.LongAdder;importjava.util.concurrent.CountDownLatch;publicclassCounterComparison{// 方案1:volatile(不安全)privatevolatileintvolatileCount=0;// 方案2:AtomicIntegerprivateAtomicIntegeratomicCount=newAtomicInteger(0);// 方案3:LongAdder(JDK8+推荐)privateLongAdderadderCount=newLongAdder();publicvoidtestVolatile()throwsInterruptedException{CountDownLatchlatch=newCountDownLatch(100);for(inti=0;i<100;i++){newThread(()->{for(intj=0;j<1000;j++){volatileCount++;// 线程不安全}latch.countDown();}).start();}latch.await();System.out.println("Volatile结果(可能不正确): "+volatileCount);}publicvoidtestAtomic()throwsInterruptedException{CountDownLatchlatch=newCountDownLatch(100);for(inti=0;i<100;i++){newThread(()->{for(intj=0;j<1000;j++){atomicCount.incrementAndGet();}latch.countDown();}).start();}latch.await();System.out.println("AtomicInteger结果: "+atomicCount.get());}publicvoidtestLongAdder()throwsInterruptedException{CountDownLatchlatch=newCountDownLatch(100);for(inti=0;i<100;i++){newThread(()->{for(intj=0;j<1000;j++){adderCount.increment();}latch.countDown();}).start();}latch.await();System.out.println("LongAdder结果: "+adderCount.sum());}publicstaticvoidmain(String[]args)throwsInterruptedException{CounterComparisontest=newCounterComparison();test.testAtomic();test.testLongAdder();test.testVolatile();}}

6.使用建议

  1. 单写多读:使用volatile
  2. 低竞争环境:使用AtomicInteger/AtomicLong
  3. 高并发写场景:使用LongAdder(JDK8+)
  4. 精确统计场景:使用Atomic系列(LongAdder的sum()可能不是实时精确值)

总结

  • volatile只解决可见性问题,不解决原子性问题
  • 对于count++这类复合操作,必须使用原子类
  • 在JDK8+的高并发写场景下,LongAdder性能通常优于AtomicLong
  • 选择哪个工具取决于具体的读写比例和并发程度
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/6/10 14:32:41

YOLO训练成本分析报表?按GPU使用量生成

YOLO训练成本分析报表&#xff1a;按GPU使用量生成 在智能制造与工业视觉系统中&#xff0c;实时目标检测早已不再是“能不能做”的问题&#xff0c;而是“值不值得做”的权衡。YOLO系列模型凭借其推理速度快、部署门槛低的优势&#xff0c;已成为产线质检、无人巡检等场景的标…

作者头像 李华
网站建设 2026/6/10 1:06:03

YOLO训练资源池划分?部门级GPU配额管理

YOLO训练资源池划分&#xff1f;部门级GPU配额管理 在一家中型智能制造企业的AI研发部&#xff0c;每周一上午总是格外紧张。算法团队要跑新版本的产线缺陷检测模型&#xff0c;实习生正尝试用YOLOv8做小目标优化实验&#xff0c;而产品经理又临时要求复现上季度某个关键指标—…

作者头像 李华
网站建设 2026/6/10 14:34:51

cache在spark执行流程中的作用

在Spark执行流程中&#xff0c;缓存&#xff08;Cache&#xff09;的作用主要体现在以下方面&#xff1a;1. 避免重复计算Spark的转换操作&#xff08;如map、filter&#xff09;具有惰性求值特性。当多次使用同一个RDD&#xff08;Resilient Distributed Dataset&#xff09;时…

作者头像 李华
网站建设 2026/6/10 14:43:56

YOLO模型支持插件扩展?自定义算子运行在GPU上

YOLO模型支持插件扩展&#xff1f;自定义算子运行在GPU上 在工业视觉、自动驾驶和智能监控等对实时性要求极高的场景中&#xff0c;目标检测模型不仅要“看得准”&#xff0c;更要“跑得快”。YOLO系列凭借其端到端的高效架构&#xff0c;已成为这些领域的首选方案。然而&#…

作者头像 李华
网站建设 2026/6/10 16:21:33

将pc本地图片传给企业微信

需求&#xff1a; 老婆最近要参加某开卷考试需要刷视频&#xff0c;但是该视频很频繁的弹二维码需要手动扫码进行验证&#xff0c;现在打算做一个程序当识别到二维码之后通过c#代码将该二维码发送到企业微信群从而实现远程扫码继续播放。 github链接&#xff1a; https://gi…

作者头像 李华
网站建设 2026/6/10 15:07:39

数据结构 可扩展哈希代码解析

可扩展哈希&#xff08;Extendible Hashing&#xff09;详解一、传统哈希的问题1.1 传统哈希扩容的痛苦c// 传统链地址法哈希表扩容 void rehash(hashtable* table) {// 1. 分配新桶数组&#xff08;通常翻倍&#xff09;// 2. 重新计算所有元素的哈希值// 3. 迁移所有数据到新…

作者头像 李华