Singleton的概念
Singleton模式是一種對象創建型模式,使用Singleton模式,可以保證為一個類只生成唯一的實例對象。也就是說,在整個程序空間中,該類只存在一個實例對象。其實,GoF對Singleton模式的定義是:保證一個類只有一個實例存在,同時提供能對該實例加以訪問的全局訪問方法。
為什么要使用Singleton模式呢?
在應用系統開發中,我們常常有以下需求:- 在多個線程之間,比如servlet環境,共享同一個資源或者操作同一個對象
- 在整個程序空間使用全局變量,共享資源
- 大規模系統中,為了性能的考慮,需要節省對象的創建時間
等等
因為Singleton模式可以保證為一個類只生成唯一的實例對象,所以這些情況,Singleton模式就派上用場了。
Singleton模式的實現
Singleton模式是設計模式中相對比較簡單的模式之一。理解以及使用方法都比較簡單。Singleton模式有多個實現方法。但目前,每一種都存在或多或少的問題。
下面我們將給出幾種實現方法,同時對它們加以比較。
第一種方法:
這是一種最簡單的實現方法。但是一種相對有效的實現方法。現在,一般推薦這一種方法作為Singleton模式的實現方法。
//1)使用final關鍵字修改class,防止子類繼承
public final class Singleton {
private static final Singleton instance = new Singleton();
private Singleton(){};
public static Singleton getInstance(){
return Singleton.instance;
}
...
}
注意上述1),2),3),4)部分,這是Singleton模式實現的幾個關鍵。
我 們注意到,這種方法沒有對instance = new Singleton()部分作同期化操作,但考慮到Singleton實例的生成只是在最初被調用時才執行一次,如果我們在調用時適當處理一下,比如在程 序的統一初期化時(SERVLET環境的情況下可以在容器被初始化時如SevletListener里)調用一下Singleton,就不會存在線程安全 問題。
第二種方法:
public final class Singleton {
private static Singleton instance;
private Singleton(){};
public static synchronized Singleton getInstance(){
if(instance == null){
instance = new Singleton();
}
return instance;
}
}
該方法把Singleton實例生成放到了getInstance方法里,同時使用synchronized解決了線程安全問題。
但如果在高并發的應用系統中,大量的線程在調用getInstance時會受到阻塞,系統的性能將受到嚴重影響。
第三種方法:
public final class Singleton {
private static Singleton instance;
private Singleton(){};
public static Singleton getInstance(){
if(instance == null){
synchronized (this) {
//double-check
if(instance == null){
instance = new Singleton();
}
}
}
return instance;
}
}
該方法也叫double-check(雙重檢查)方法,把線程同步synchronized放到只會被執行一次的同步塊里。該方法雖然解消了性能瓶頸問題,但該方法被指出并不是線程安全的(不同步的情況下引用類型不是線程安全的)。
第四種方法:
public final class Singleton {
private volatile static Singleton instance;
private Singleton(){};
public static Singleton getInstance(){
if(instance == null){
synchronized (this) {
//double-check
if(instance == null){
instance = new Singleton();
}
}
}
return instance;
}
}
該方法在第三種方法的基礎上,為Singleton instance的定義加上volatile關鍵字修飾,該方法也被稱為double-check volatile方法。但該方法卻依奈不同的編譯器。也就是說,在某些編譯環境中,第四種方法也是非線程安全的。