Java中不同显式synchronized锁下可变对象的修改可见性问题
问题解答
结论
setFeature对mFeature的修改不保证对useFeature可见。
原因说明
Java内存模型(JMM)中synchronized的可见性保证有明确的适用前提:只有同一个锁的解锁操作和后续的加锁操作之间才存在happens-before关系,也就是前一个线程释放锁之前的所有写入,对后一个拿到同一把锁的线程才可见。
你代码里两个同步块用的完全是不同的锁:
setFeature方法用的是FeatureService.class类对象作为全局锁useFeature方法用的是每个FeatureService实例独立创建的MUTEX实例作为锁
两者没有任何同步关联,所以不存在可见性保证,useFeature很可能读到的是旧的mFeature缓存值。
额外需要注意的是,mFeature是静态全局变量,而MUTEX是实例变量,就算不考虑setFeature的修改可见性,不同FeatureService实例调用useFeature时用的是不同的锁,互相之间也不会有互斥效果,同步逻辑完全失效。
修复建议
- 方案1:把锁统一,要么都用
FeatureService.class作为锁,要么把MUTEX也改成静态变量,两个方法都用这个静态锁 - 方案2:如果只需要保证可见性不需要原子性,可以直接给
mFeature加volatile修饰,跳过锁的可见性绑定限制
// 示例修复:统一用静态锁 public class FeatureService { private static Feature mFeature= null; // 改成静态全局锁 private static final Object MUTEX = new Object(); ... static void setFeature(Feature feature){ // doSomething synchronized (MUTEX){ mFeature = feature; // doSomething } // doSomething } public void useFeature(...){ // doSomething synchronized (MUTEX){ someFunction(mFeature); // doSomething } // doSomething } }
内容的提问来源于stack exchange,提问作者Willy
相关产品推荐
相关产品推荐

