標籤:

單例模式的進化史

public final class LazySingleton { private static LazySingleton singObj = null; private LazySingleton(){ } public static LazySingleton getSingleInstance(){ if(null == singObj ) //A線程執行       singObj = new LazySingleton(); //B線程執行 return singObj } }

這種方式不是線程安全的。

public final class ThreadSafeSingleton { private static ThreadSafeSingleton singObj = null; private ThreadSafeSingleton(){ } public static synchronized ThreadSafeSingleton getSingleInstance(){ if(null == singObj ) singObj = new ThreadSafeSingleton(); return singObj } }

這種方式把synchronized 加到整個方法上,會影響並發性能。

public final class DoubleCheckedSingleton { private static DoubleCheckedSingleton singObj = null; private DoubleCheckedSingleton(){ } public static DoubleCheckedSingleton getSingleInstance(){ if(null == singObj ) { //第一次檢查 Synchronized(DoubleCheckedSingleton.class){ //加鎖 if(null == singObj) //第二次檢查 singObj = new DoubleCheckedSingleton(); } } return singObj } }

上一種方式的優化方案是減小鎖的粒度,這裡使用了一種技巧:雙重檢查鎖定(double-checked locking)。但這種方案也並非完全安全,具體原因請見參考資料。解決方案是用volatile(防止指令重排序) 修飾singObj

private volatile static DoubleCheckedSingleton singObj

public final class Singleton { private static Singleton singObj = new Singleton(); private Singleton(){ } public static Singleton getSingleInstance(){ return singObj } }

這種方式的缺點是提前載入對象,也許對象很大卻暫時用不到,提前載入會造成內存的浪費。因為希望在用到它時再載入,也就是延遲載入(Lazy-load Singleton)。

class Singleton { private static class SingletonHolder { public final static Singleton instance = new Singleton(); } public static Singleton getInstance() { return SingletonHolder.instance; }}

Initialization on Demand Holder模式,這種方法使用內部類來做到延遲載入對象,在初始化這個內部類的時候,JLS(Java Language Sepcification)會保證這個類的線程安全(the class initialization phase is guaranteed by the JLS to be serial)。這種寫法最大的美在於,完全使用了Java虛擬機的機制進行同步保證,沒有一個同步的關鍵字

參考資料:Java單例中的延遲載入 - CSDN博客

UML和設計模式:看懂UML類圖和時序圖 - Graphic Design Patterns


推薦閱讀:

(原創)關於設計模式的理解:策略模式
Go編程技巧之「延後抽象」
《Node.js設計模式(第2版)》試讀 & 送書活動
裝飾者模式理解
設計模式之關係

TAG:設計模式 |