設計模式23中
設計模式詳解
====================單例=======================
在JDK 5之後,Java使用了新的內存模型。volatile關鍵字有了明確的語義——在JDK1.5之前,volatile是個關鍵字,但是並沒有明確的規定其用途——被volatile修飾的寫變量不能和之前的讀寫代碼調整,讀變量不能和之後的讀寫代碼調整!因此,只要我們簡單的把instance加上volatile關鍵字就可以了。
public class SingletonClass {
private volatile static SingletonClass instance = null;
public static SingletonClass getInstance() {
if (instance == null) {
synchronized (SingletonClass.class) {
if(instance == null) {
instance = new SingletonClass();
}
}
}
return instance;
}
private SingletonClass() {
}
}
然而,這只是JDK1.5之後的Java的解決方案,那之前版本呢?其實,還有另外的一種解決方案,並不會受到Java版本的影響:
public class SingletonClass {
private static class SingletonClassInstance {
private static final SingletonClass instance = new SingletonClass();
}
public static SingletonClass getInstance() {
return SingletonClassInstance.instance;
}
private SingletonClass() {
}
}
在這一版本的單例模式實現代碼中,我們使用了Java的靜態內部類。這一技術是被JVM明確說明了的,因此不存在任何二義性。在這段代碼中,因為SingletonClass沒有static的屬性,因此並不會被初始化。直到調用getInstance()的時候,會首先加載SingletonClassInstance類,這個類有一個static的SingletonClass實例,因此需要調用SingletonClass的構造方法,然後getInstance()將把這個內部類的instance返回給使用者。由於這個instance是static的,因此並不會構造多次。
由於SingletonClassInstance是私有靜態內部類,所以不會被其他類知道,同樣,static語義也要求不會有多個實例存在。並且,JSL規範定義,類的構造必須是原子性的,非並發的,因此不需要加同步塊。同樣,由於這個構造是並發的,所以getInstance()也並不需要加同步。
至此,我們完整的了解了單例模式在Java語言中的時候,提出了兩種解決方案。個人偏向於第二種,並且Effiective Java也推薦的這種方式。
設計模式23中