我对此实例化方法有疑问:
从this网站上说:
class Singleton
{
private static Singleton instance;
private Singleton()
{
System.out.println("Singleton(): Initializing Instance");
}
public static Singleton getInstance()
{
if (instance == null)
{
synchronized(Singleton.class)
{
if (instance == null)
{
System.out.println("getInstance(): First time getInstance was invoked!");
instance = new Singleton();
}
}
}
return instance;
}
public void doSomething()
{
System.out.println("doSomething(): Singleton does something!");
}
}
然而,从Elisabeth Freeman,Eric Freeman,Bert Bates,Kathy Sierra,Elisabeth Robson所着的“Head First Design Pattern”一书中,他们使用相同的方法实例化Singleton,唯一的区别是他们将私有静态成员声明为volatile
他们认为volatile
声明了这一点。为了在线程之间建立正确的“幸福关系”,不应该宣布“临界区”同步吗?
答案 0 :(得分:2)
根据定义,使用volatile变量可降低内存一致性错误的风险,因为对volatile变量的任何写入都会建立与之后读取同一变量的先发生关系。
问题是乱序写入可能允许在执行Singleton构造函数之前返回实例引用。
线程A注意到该值未初始化,因此它获得锁定并开始初始化该值。
由于编程语言的语义,允许编译器生成的代码在A完成初始化之前更新共享变量以指向部分构造的对象。例如,在Java中,如果内联对构造函数的调用,那么一旦分配了存储但在内联构造函数初始化对象之前,共享变量可能会立即更新。
线程B注意到共享变量已初始化(或显示),并返回其值。因为线程B认为该值已经初始化,所以它不会获得锁定。如果B在B看到A完成的所有初始化之前使用该对象(因为A尚未完成初始化或者因为对象中的某些初始化值尚未渗透到内存B使用(缓存一致性)) ,程序可能会崩溃。
阅读此Wiki以获得对事物的清晰解释:http://en.wikipedia.org/wiki/Double_checked_locking_pattern#Usage_in_Java