ReentrantReadWriteLock与Java内存模型交互及线程同步调试疑惑
ReentrantReadWriteLock写锁同步后的内存可见性问题
写锁的内存语义(基于Java内存模型)
ReentrantReadWriteLock的写锁完全遵循Java内存模型的同步规则:
- 写锁释放操作:会将当前线程本地缓存的所有共享变量修改刷新到主内存,同时释放锁资源
- 写锁获取操作:会使当前线程的本地缓存失效,后续读取共享变量必须从主内存重新加载
- 从happens-before规则来看:线程A释放写锁的动作,happens-before线程B获取同一个写锁的动作。这意味着线程A在释放锁前的所有共享变量修改,线程B在获取锁后的所有操作都应该能看到。
针对你的场景分析
按你给出的事件顺序:
- 线程A的写锁释放已经把long变量的新值同步到主内存
- 线程B在步骤4获取写锁时,会触发本地缓存失效,此时它的内存视图已经和主内存同步——也就是说,线程B在获取写锁之后,任何对该long变量的读取都应该拿到新值
- 你观察到线程B在步骤6(释放锁后)读到旧值,这不符合JMM的规范,大概率是以下原因之一:
- 事件顺序确认有误:线程B的读取操作可能实际发生在释放锁之前,甚至是获取锁之前(比如代码逻辑的分支、异步操作导致顺序混乱)
- 锁实例不唯一:线程A和线程B使用的不是同一个ReentrantReadWriteLock实例,导致写锁的同步屏障完全不起作用
- JIT重排序优化:极端情况下,JIT编译器可能对线程B的读取操作做了重排序,跳过了内存同步步骤(可以通过添加
volatile修饰变量,或者在读取前插入内存屏障Unsafe.loadFence()来验证)
排查建议
- 先确认线程A和线程B使用的是同一个ReentrantReadWriteLock对象,这是同步生效的前提
- 在线程B获取写锁后立即读取变量并打印,对比释放锁后的读取结果,判断同步是否在获取锁时就已生效
- 临时将long变量改为
volatile类型,如果现象消失,说明原问题确实是内存可见性导致的,进一步排查锁的使用逻辑
内容的提问来源于stack exchange,提问作者ICR
相关产品推荐
相关产品推荐

