以下是单例模式的双检查实现。线程A正在执行test=new Test();
线路,但同时,线程B首先检查test
的值。 test
的值是什么?
class Test {
private Test test;
private Test() {
}
public static Test get() {
if (test == null) { // Thread B. When object is being created,
// what's value of test. Is it always null before
// Thread B new object?
synchronized (test.getClass()) {
if (test == null) {
test = new Test(); // Thread A. This thread is creating object.
}
}
}
return test;
}
}
添加
如果它不是单身模式的正确版本,volatile
关键字可以解决问题吗?也就是说,private volatile Test test;
它是未知的。这就是为什么此实现被认为是错误的。
test = new Test()
首先创建对象,然后将其分配给test
,然后初始化。
因此,线程B
会引用对象,但可能不会初始化。
这似乎也是一种很好的方法在问题中),我们也不需要急切的初始化来消除这一点:
public class BillPughSingleton {
private BillPughSingleton(){}
private static class SingletonHelper{
private static final BillPughSingleton INSTANCE = new BillPughSingleton();
}
public static BillPughSingleton getInstance(){
return SingletonHelper.INSTANCE;
}
}
请注意包含Singleton类实例的private inner static class
。加载单例类时,SingletonHelper class
不会加载到内存中,并且仅当有人调用getInstance
方法时,此类将加载并创建Singleton类实例。
这是单身类别类最广泛使用的方法之一,因为它不需要同步。
如果它不是单例模式的正确版本,则可以挥发关键字 解决问题?
的确,这个:
private Test test;
应声明:
private volatile Test test;
否则,线程的内存B
May 保留 May 的test
的陈旧版本是null
,而线程A
用私有构造函数对其进行了评估。
<<br> <<br> <<br> <<br> <<br> <<br> <<br> <<br> <<br> <<br>
/p>
通过将test
指定为volatile
,您可以确保其他线程可以看到一个线程执行的任何分配。
现在,这种实现单例的方式不是很直(双条件语句加显式同步)。
作为两个很好的替代方案,您可以使用Enum Singleton Idiom:
public enum Test implements TestInterface{
SINGLETON;
...
}
请注意,建议接口编写自然测试的实现并能够切换到其他实现。
否则Bill Pugh Singleton Idiom(这里是渴望的风味):
public class Test{
// executed as soon as the T class is loaded by the classLoader
private static Test instance = new Test();
private Test() {
}
public static TestgetInstance() {
return instance;
}
}