Brian Goetz廉价读写锁示例中volatile修饰是否冗余?
关于CheesyCounter中volatile是否冗余的澄清
你的思路有一定道理,但忽略了Java内存模型里一个关键细节——同步块的可见性保障只覆盖进入/退出同步块的操作,无锁的读操作并不在这个保障范围内。咱们一步步拆解清楚:
你觉得volatile冗余的逻辑误区
你说的没错:所有写入value的操作都在synchronized块中执行,当线程退出同步块时,会将工作内存中的value刷新到主内存,这部分完全符合JMM的happens-before规则。但问题恰恰出在**无锁的读操作getValue()**上。
去掉volatile会产生什么问题?
当线程调用getValue()时,它没有进入任何同步块,JMM不会强制它从主内存读取value的最新值。读线程的工作内存中可能已经缓存了value的旧副本,并且会一直复用这个副本,完全看不到其他线程在同步块中更新到主内存的新值。
举个实际场景就能明白:
- 线程A循环调用
increment(),每次都在同步块里更新value并刷新到主内存 - 线程B循环调用
getValue(),如果没有volatile修饰value,B可能一直返回最初的0,永远看不到A更新后的数值
volatile在这里的核心作用
加上volatile修饰后,会强制两个关键行为:
- 每次
getValue()读取value时,必须直接从主内存获取最新值,不会复用工作内存的缓存副本 - 每次写入
value(即使在同步块里)后,立即刷新到主内存(这部分和同步块的效果重叠,但核心是修正了无锁读的行为)
简单总结:同步块保证了写入操作的原子性和写入到主内存的动作,而volatile保证了无锁读操作能看到主内存的最新值,二者是互补关系,完全不是冗余的。
内容的提问来源于stack exchange,提问作者Javadee
相关产品推荐
相关产品推荐

