Java 多线程中的单例-各种场景
以下两个代码在多线程环境方面有什么不同 代码1: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
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
只加载一次,因为我可以根据需要多次初始化静态
变量<代码>静态仅将变量标记为在类的所有实例之间共享。