java單例模式與線程安全實例分析

設計模式在軟件架構設計中被經常使用,掌握常用的設計模式對於設計軟件系統非常重要。單例模式作為設計模式中最簡單和常用的一種模式,java中單例模式具有多種實現方式,以下會對各種實現進行解析。

1、單例模式概念:

顧名思義,單例模式指的是在軟件系統運行過程中,某個類只存在一個實例。因此一個類實現單例模式時需要具備以下3個條件:

1)類的內部定義一個該類的靜態私有成員變量;

2)構造方法為私有;

3)提供靜態工廠方法,供外部獲取類的實例;

java單例模式與線程安全實例分析

2、單例模式實現方式:

1)懶漢式單例

public class Singleton {

private static Singleton instance;

private Singleton() {

}

public synchronized static Singleton getInstance() {

if (instance == null) {

instance = new Singleton();

}

return instance;

}

}

懶漢式單例即在使用使用時才創建類的實例,工廠方法增加類synchronized關鍵字以保證線程安全。在多線程訪問的環境下,同步方法導致系統性能下降。優點在於,類加載時不用自行實例化對象,避免加載緩慢。

2)餓漢式單例

public class Singleton {

private static Singleton instance = new Singleton();

private Singleton() {

}

public static Singleton getInstance() {

if (instance == null) {

instance = new Singleton();

}

return instance;

}

}

餓漢式單例,在類加載式自行實例化對象。優點在於多線程環境下不會出現線程安全問題,因為類只加載一次。缺點在於,系統加載時消耗額外資源,如果該實例沒有使用的情況會造成資源浪費。

3)雙重檢測單例

public class Singleton {

private static volatile Singleton instance;

private Singleton() {

}

public static Singleton getInstance() {

if (instance == null) {

synchronized (Singleton.class) {

if (instance == null) {

instance = new Singleton();

}

}

}

return instance;

}

}

雙重檢測鎖定(Double-Check Locking)方案屬於懶漢式,使用延時加載技術,避免類加載時任務過重和造成資源浪費,同時將synchronized關鍵字加在代碼塊中,減少線程同步鎖定以提升系統性能。instance實例使用了volatile關鍵字修飾,主要是避免在多線程環境下由於編譯器進行的重排序操作而導致的線程安全問題。JVM在創建一個對象時會進行以下步驟:

1)分配對象內存空間;

2)初始化對象;

3)設置instance指向分配的內存地址;

編譯器為了優化性能,可能會將2、3操作調換順序,假設A線程在執行new Singleton()方法時,由於2、3操作重排序,而初始化對象操作尚未完成時釋放了鎖。線程B獲取鎖之後會發現instance已經不為空,當線程B獲取到instance對象後如果直接使用就會出錯,原因就是對象沒有進行初始化操作。而volatile關鍵字能避免重排序,因此能保證線程安全。總體上來說,雙重檢測由於加了鎖,多線程併發下還是會有效率問題。

4)枚舉單例

public enum Singleton {

INSTANCE

}

枚舉單例模式,不會存在線程安全問題,不過在Android平臺下,枚舉類性能相對較低。

5)靜態內部類單例

public classSingleton {

private Singleton() {

}

public static Singleton getInstance() {

return SingletonFactory.instance;

}

static class SingletonFactory {

private final static Singleton instance = new Singleton();

}

}

靜態內部類單例模式是一種比較優秀的實現方式,也是《Effective Java》書中推薦的方式。一方面,使用延時加載,使用時才進行對象初始化,也不會造成造成資源浪費;另一方面,由於JVM在類的加載時已經做了同步處理,不會出現線程安全問題。

結束語

文中介紹單例模式的一些基礎知識點,以及多種實現方式的優缺點分析。在日常開發中,推薦使用靜態內部類實現單例模式。相對其他設計模式而言,單例模式是非常簡單的。


分享到:


相關文章: