1. 程式人生 > >19、設計模式之單例模式-懶漢式

19、設計模式之單例模式-懶漢式

/**
 * 懶漢式-單例模式
 * 多執行緒模式慎用,單例模式會失效,為解決這一問題,可以在靜態方法上加“synchronized”表明鎖住該類本身,同一時間點只有一個執行緒可以訪問該方法
 * 該方法雖然可以解決單例失效的問題,但卻非常的消耗資源
 */
public class LazySingleton {
    private static LazySingleton instance = null;

    private LazySingleton(){

    }

    private synchronized static LazySingleton getInstance(){
        if(instance==null){
            instance = new LazySingleton();
        }
        return instance;
    }

    /**
     * 與上述方法等效
     * @return
     */
    private static LazySingleton getNewInstance(){
        synchronized(LazySingleton.class) {
            if (instance == null) {
                instance = new LazySingleton();
            }
        }
        return instance;
    }
}

進一步完善,解決資源佔用過多的問題

/**
 * 引入雙重鎖概念,完善懶漢式-單例模式
 */
public class LazyDoubleCheckSingleton {

    private volatile static LazyDoubleCheckSingleton instance = null;

    private LazyDoubleCheckSingleton(){

    }

    public static LazyDoubleCheckSingleton getInstance(){
        if(instance==null){
            synchronized (LazyDoubleCheckSingleton.class) {
                if(instance==null) {
                    instance = new LazyDoubleCheckSingleton();
                    // 這種方式雖然極大地解決了資源佔用多過的問題,但也是存線上程安全性問題
                    // new 一個物件實際執行了三步操作,如下
                    // 1、為物件分配記憶體地址
                    // 2、初始化物件
                    // 3、將instance指向 新分配的記憶體地址
                    // 正常情況下,執行順序1->2->3 如此執行,但多執行緒會造成重排序現象1->3->2,如要禁止該現象發生,
                    // 只需要在instance變數宣告上加入一個關鍵字“volatile”,
                    // 多執行緒下 系統會有共享記憶體,volatile會使所有執行緒都能看見該變數的最新狀態,
                    // 在賦值的時候,會將當前行快取資料寫回到共享記憶體,這樣其他執行緒快取的資料就會失效,從而再次向共享記憶體獲取該變數的最新資料
                }
            }
        }
        return instance;
    }
}

第二種完善方式,靜態內部類

/**
 * 完善懶漢式-單例模式 第二種方式:靜態內部類
 * 由於靜態內部類被呼叫時,系統會先獲取類物件鎖,這樣一來,多執行緒之間就遮蔽了StaticInnerClassSingleton 類例項化的全過程,
 * 重排序現象僅對當前執行緒可見且有效
 */
public class StaticInnerClassSingleton {

    private StaticInnerClassSingleton(){

    }
    private static class InnerClass{
        private static StaticInnerClassSingleton instance = new StaticInnerClassSingleton();
    }

    public static StaticInnerClassSingleton getInstance(){
        return InnerClass.instance;
    }
}

【切記】單例模式,一定要記得建立私有建構函式