Java 多线程中的单例-各种场景

Java 多线程中的单例-各种场景,java,multithreading,singleton,Java,Multithreading,Singleton,以下两个代码在多线程环境方面有什么不同 代码1: public class Singleton { private Singleton() {} private static class SingletonHolder { private static final Singleton INSTANCE = new Singleton(); } public static Singleton getInstance() { return SingletonHolder.INS

以下两个代码在多线程环境方面有什么不同

代码1:

public class Singleton {
private Singleton() {}

private static class SingletonHolder { 
    private static final Singleton INSTANCE = new Singleton();
}

public static Singleton getInstance() {
    return SingletonHolder.INSTANCE;
}
}
代码2:

class Singleton {
private static Singleton uniqueInstance;

private Singleton() { ... }

public static Singleton getInstance() {
    if (uniqueInstance == null) {
        uniqueInstance = new Singleton();
    }

    return uniqueInstance;
}
}
为什么代码2在多线程环境中不能工作,因为它还声明了一个静态变量,一旦类被加载就会被加载&因此它只有一个实例


谢谢

多个线程可能位于:

if (uniqueInstance == null) {
...
}

同时执行条件。

请记住,在给定时间,可以有多个线程调用
getInstance

在示例1中,
uniqueInstance
成员的初始值设定项保证只在类加载时运行一次

在示例2中,由于初始化是在
getInstance
中内联进行的,因此多个线程可以独立且并发地将
uniqueInstance
成员变量查找为
null
。然后,每个线程将调用
new Singleton()
,结果不确定,这取决于两个(或更多)线程的计时

例如,为了工作,您可以(例如)在
getInstance
方法上添加
synchronized


您关于变量在类加载时被完全初始化的评论(例如1)是正确的,但在2中不是正确的-在示例2中,成员变量在类加载时被设置为
null
,但在以后的第一次调用期间被对象实例填充若要
getInstance

从示例2中删除空检查条件,该怎么办?在这种情况下,当多个线程尝试调用getInstance()时,它将看到第一个线程已经初始化了它,对吗?那么,为什么我们说示例2不是线程安全的呢?这会让事情变得更糟,因为这样,singleton的每个用户都会得到自己的类实例。检查是必需的,但必须以线程安全的方式进行,通常使用
synchronized
。但我将其声明为static&static不应该只加载一次吗?正确。示例1正常工作的原因是您将加载时间与成员初始化耦合在一起。在示例2中,成员初始化与对
getInstance
的“第一次调用”相耦合。问题是,在多线程配置中,对函数的“第一次调用”是没有意义的,没有同步来强制执行“第一次调用”的并发候选线程(线程)中的赢家。可以更恰当地说,
final
只加载一次,因为我可以根据需要多次初始化
静态
变量<代码>静态仅将变量标记为在类的所有实例之间共享。