Java多线程中修改对象引用而非更新对象本身是否需要加锁?
问题结论
不需要加锁,但你必须给publicDataObject变量增加volatile修饰符,才能保证线程安全。
核心原因分析
- Java中引用类型的赋值操作本身是原子操作,不会出现半更新的无效引用,读线程要么拿到更新前的旧List引用,要么拿到更新后的新List引用,不会出现中间状态。
- 你面临的风险不是原子性问题,而是Java内存模型的可见性和指令重排序问题:
- 若没有同步修饰,写线程对
publicDataObject的更新可能只停留在CPU本地缓存,不会同步到主内存,其他读线程会长期读取到旧的List引用,感知不到更新。 - 若没有同步修饰,JVM可能对指令重排序,将
publicDataObject的赋值操作提前到CreateNewDataObject()的List初始化逻辑之前,导致读线程拿到还未完成元素填充的不完整List实例。
- 若没有同步修饰,写线程对
场景适配方案
因为你只有一个写线程,不存在多写竞争,所以不需要加重量级的锁:
- 直接将变量声明修改为
public volatile List<DataObject> publicDataObject即可。volatile会禁止指令重排序,同时强制变量的读写都直接操作主内存,保证所有读线程都能及时拿到最新的完整List引用,性能开销远低于加锁。 - 若后续扩展为多写线程场景,才需要加锁保证多个写操作的原子性。
额外注意事项
上述安全保证仅针对publicDataObject的引用赋值操作:如果读线程拿到List引用后,会修改List内部的元素或者DataObject的属性,还需要额外针对元素操作做同步防护。
内容的提问来源于stack exchange,提问作者Wei
相关产品推荐
相关产品推荐

