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

ReentrantLock的ConditionObject字段为何未用volatile修饰?

关于ConditionObject中firstWaiter/lastWaiter无volatile修饰的内存一致性疑问

已知ConditionObject的firstWaiter和lastWaiter字段未被volatile修饰,但只有持有独占锁的线程才能修改这两个字段。这里有个疑问:如果一个线程修改这两个字段后,另一个线程读取时会不会因为CPU缓存没拿到最新值导致不一致?为什么不需要volatile就能保证内存一致性?

对应的代码实现:

public class ConditionObject implements Condition, java.io.Serializable {
    private static final long serialVersionUID = 1173984872572414699L;

    /** 这两个字段未被volatile修饰,可能被不同线程修改 */
    private transient ConditionNode firstWaiter;
    private transient ConditionNode lastWaiter;
}

核心答案:独占锁的内存语义已经兜底

其实根本原因在于,所有对这两个字段的读写操作,都必须在持有独占锁的前提下执行,锁的获取与释放本身就自带了内存屏障的效果,完全覆盖了volatile的作用:

  • 当线程释放独占锁时,JMM会强制把该线程本地缓存里的所有修改(包括对firstWaiter/lastWaiter的修改)刷新到主内存中,确保修改对外可见。
  • 当另一个线程获取同一把独占锁时,JMM会让该线程的本地缓存直接失效,必须从主内存重新读取所有共享变量的最新值,自然也能拿到这两个字段的最新状态。

再结合Condition的实际运行逻辑看:

  • 调用await方法时,线程会先释放锁,进入Condition的等待队列(此时修改firstWaiter/lastWaiter的操作是在持有锁时完成的);被signal唤醒后,线程又会重新竞争获取锁,之后才能访问等待队列的节点。
  • 调用signal/signalAll方法时,只有持有锁的线程才能执行,修改等待队列节点的操作同样在锁的临界区内完成。

简单说,这两个字段的读写完全被锁的临界区包裹,锁的内存语义已经保证了修改的可见性和有序性,根本不需要额外加volatile。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.26 22:26:00