是否需将Supplier类成员声明为volatile以保障线程安全?
heavy成员是否需要声明为volatile 结论:是的,必须将heavy成员声明为volatile,具体原因如下:
可见性无法保证
当线程在synchronized方法createAndCacheHeavy()中修改heavy的引用(从方法引用替换为HeavyFactory实例)时,如果heavy未标记为volatile,其他线程在非同步的getHeavy()方法中读取heavy时,可能无法感知到这个最新的引用变化。这会导致其他线程反复触发createAndCacheHeavy(),甚至多次创建Heavy实例,完全违背懒加载单例的设计目的。happens-before关系缺失
createAndCacheHeavy()作为同步方法,仅能保证锁释放前的写操作对后续获取同一锁的线程可见,但对未获取锁的getHeavy()调用线程不提供可见性保障。非同步的getHeavy()读取heavy时没有触发内存屏障,无法确保读到的是最新的heavy引用。变种DCL模式的要求
这段代码本质是变种的双重检查锁定(DCL)模式:第一次读取heavy是非同步的,进入同步方法后再次检查heavy状态。在DCL模式中,懒加载变量必须声明为volatile,否则会出现指令重排序或可见性问题,这里的heavy变量也遵循相同规则。
修正后的heavy声明应为:
private volatile Supplier<Heavy> heavy = this::createAndCacheHeavy;
修改后,heavy的写操作(同步方法内)会对所有后续读操作(getHeavy()内)建立happens-before关系,确保所有线程都能看到最新的heavy引用,避免重复创建对象或读取无效的Supplier实例。
内容的提问来源于stack exchange,提问作者Dimitar Traykov

