You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

对象唤醒条件变量是否需加volatile修饰符?无volatile时为何可正常运行

Java并发变量可见性问题解答

你的疑问本质是对Java内存模型中可见性的触发规则理解不够全面,synchronized关键字本身就自带完整的可见性保证,即使变量没有加volatile修饰,只要读写都在同一个锁的同步块保护下,就能正常工作。

核心规则依据

根据JMM的管程锁定happens-before规则:对同一个锁的解锁操作,先行发生于后续对这个锁的加锁操作。所有解锁前对共享变量的修改,对后续加锁后执行的代码都完全可见。
具体到你给出的代码,可见性保证分为两个环节:

  • 线程进入synchronized方法抢到锁时,会直接清空当前线程工作内存中该锁保护的所有共享变量的缓存副本,强制从主内存读取最新值。你代码中每次循环判断fActiveTestDeathCount的值、或者wait()被唤醒重新抢到锁时,拿到的都是主内存的最新值,不会用线程本地缓存的旧值。
  • 所有修改fActiveTestDeathCount的操作,只要是在同一个对象锁的synchronized块中执行的,线程释放锁时就会把工作内存中的修改强制刷新回主内存,保证其他线程能读取到最新值。

常见误区说明

注意:上述可见性保证的前提是所有对fActiveTestDeathCount的读写操作,都被同一个对象锁的synchronized块保护。如果存在线程未持有同一个锁就直接修改该变量的场景,修改结果不会同步到主内存,执行waitUntilFinished的线程依然会读到旧值,程序就会出现逻辑错误。
你最初给变量加volatile其实是多余的,只要满足所有读写都加同一个锁的前提,不需要额外加volatile。volatile的适用场景是无锁的单写多读场景,通过内存屏障禁止指令重排序、保证可见性,不需要加锁就能实现跨线程的变量可见。
你猜测的「线程被唤醒后失效工作内存变量、从主内存同步数据」是完全正确的,底层就是JVM在synchronized的入口、出口位置插入了对应的内存屏障指令,保证缓存一致性,实现跨线程的可见性。


内容的提问来源于stack exchange,提问作者Terrence

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.01 01:00:05