Java 这段代码是线程安全单例设计模式的正确示例吗?

Java 这段代码是线程安全单例设计模式的正确示例吗?,java,multithreading,singleton,Java,Multithreading,Singleton,下面的代码是Java中线程安全单例模式的正确示例吗 class Singleton { private static Singleton INSTANCE = new Singleton(); public static Singleton getInstance() { return INSTANCE; } } 由于静态成员只在JVM加载类时初始化一次,而JVM保证是线程安全的,所以这不就是线程安全的单例类(早期加载)的上述代码示例吗 以上说

下面的代码是Java中线程安全单例模式的正确示例吗

    class Singleton {
    private static Singleton INSTANCE = new Singleton();

    public static Singleton getInstance() {
        return INSTANCE;
    }
}
由于静态成员只在JVM加载类时初始化一次,而JVM保证是线程安全的,所以这不就是线程安全的单例类(早期加载)的上述代码示例吗


以上说法有什么不对吗?如果是,那么将其转换为线程安全的单例类需要进行哪些最低限度的更改?

这由JLS保证是安全的。请参阅:“由于JLS保证类初始化阶段是连续的,即非并发的,因此在加载和初始化期间,静态getInstance方法中不需要进一步同步。”

holder模式比您想要的更复杂,但重要的是无论在哪个类中声明,static final Something INSTANCE=new Something()都是安全的。与现有模式相比,holder模式的优点是,只有在第一次使用单例时才会初始化它。如果您想在初始化
Singleton
实例的成本很高的情况下访问
Singleton
类中的其他静态成员,这将非常有用


正如和指出的,您应该声明
实例
字段
最终
,以确保不会意外地将不同的
单例
实例分配给变量。您还应该声明一个私有的无参数
Singleton()
构造函数,以防止创建其他实例。为了使它更加防弹,您应该声明
Singleton
final
,这样您就不能用
public
构造函数对它进行子类化。

它是完全线程安全的。您关于这个类的初始化的陈述是正确的,但是实例不是final,因此,当您将另一个对象分配给变量时,可能会出现一些不可预见的行为。请参阅=>您也可以查看=>谢谢。第一个链接仅指惰性初始化示例,正如第二个链接所提到的,您在链接中所指的是按需初始化持有者习惯用法。在操作代码中它不是懒惰的。重要的一点是,
static final Something INSTANCE=new Something()
是安全的,无论它在哪个类中声明。即使它不是
final
,就初始化而言它也是线程安全的。但是,这在其他方面是危险的。所有单例引用都应该声明为
final
,因为根据定义,应该只创建一个实例,因此保留重新分配引用的能力是没有意义的(除非您希望在将来某个时间点有条件地
null
将其清除)。若要回答您的问题,它不会更改您发布的代码的行为。但是,标记字段
final
将防止您意外编写类似
void setInstance(Singleton o){INSTANCE=o;}
,这可能是线程不安全的,并且由于其他原因也是非常错误的。