使用锁能否替代volatile解决问题?Java线程安全测试存疑
问题1:使用锁能否缓解volatile关键字所处理的问题?
可以,而且锁的能力覆盖了volatile的作用范围,甚至能解决更多问题:
- volatile的核心作用是保证变量的可见性和禁止指令重排序,但无法保证复合操作的原子性(比如
i++这类读-改-写操作)。 - 以
synchronized为例,它的内存语义是:进入同步块时,会将线程工作内存中的变量刷新为主内存的最新值;退出同步块时,会将工作内存中修改后的变量写回主内存。同时,synchronized还能保证同步块内代码的原子性。 - 所以锁不仅能解决volatile处理的可见性、指令重排序问题,还能处理volatile搞不定的原子性场景,完全可以替代volatile解决它对应的问题。
问题2:为何未复现预期的线程安全问题?
这是预期结果,不是巧合,核心原因是你用了synchronized锁,它的内存语义已经替代了volatile的可见性保障:
- happens-before规则:同一个锁的解锁操作,happens-before后续对该锁的加锁操作。也就是说,
update方法退出同步块(解锁)时,currMap的新值已经被写回主内存;read方法进入同步块(加锁)时,会从主内存读取currMap的最新值,不会读到旧缓存。 - 结合你的代码分析:
update里的currMap = newMap操作在同步块内,退出时会强制刷新到主内存;read方法在同步块内读取currMap,必然会拿到主内存的最新引用,而不是线程本地缓存的旧引用;- 哪怕
currMap没加volatile,锁的内存屏障已经保证了变量的可见性,所以read永远不会读到被移除了key=0的旧map,自然不会返回-1,你的断言assertTrue(readWrong.get() > 0)会一直失败。
内容的提问来源于stack exchange,提问作者petabyte
相关产品推荐
相关产品推荐

