为什么单例线程中的这个静态最终变量是安全的?

2022-09-03 09:38:33

阅读这个网站,我发现了这个

[The] 行仅在实际使用类时执行,这负责延迟实例化,并且是否保证它是线程安全的。private static final Foo INSTANCE = new Foo();

为什么这保证是线程安全的?因为此字段是最终字段?还是出于其他原因?


答案 1

因为它是最终的,是的。Final 变量具有特殊的线程安全语义,因为其他线程可以保证至少以构造函数完成时的状态看到最终字段。

这是在JLS 17.5中,尽管那里的语言有点密集。这些语义是在Java 1.5中引入的,特别是由JSR-133引入的。有关 JSR-133 及其各种含义的非规范讨论,请参阅此页面。

请注意,如果在实例的构造函数之后修改实例,则一定是线程安全的。在这种情况下,您必须采取通常的螺纹安全预防措施,以确保边缘发生之前。

我相当确定(虽然不是100%),只有一个线程进行类初始化的事实在这里不是一个因素。确实,该类仅由一个线程初始化,但我不相信在该线程之间建立任何特定发生 - 在该线程之间建立任何其他使用该类的线程(除了不必重新初始化该类的其他线程)之间建立任何特定事件。因此,如果没有关键字,另一个线程将能够看到对象的部分构造实例。JMM 定义的特定“发生前”边在 JLS 17.4.5 中,并且未在此处列出类初始化。final


答案 2

类构造函数和静态/实例初始值设定项保证以原子方式执行,并且由于等效于private static final FOO INSTANCE = new FOO;

private static final FOO INSTANCE;

static{
    INSTANCE = new FOO();
}

这种情况属于上述类别。