單例模式和volatile關鍵字

??越來越感覺編程的世界是真正符合自然的世界,真正遵循自然的規律。在程序的世界中事情幾乎是平等的,即使不平等也是有據可循,任何技術問題也可討論的,無論結果如何,總是0與1的差別。 同樣真實世界中的事物放到程序世界中也變得那么客觀起來,正如這篇文章的主角Singleton Design Pattern一樣。
??單例模式可以有多種實現方法,需要根據情況作出正確的選擇。

  • 餓漢式
public class Singleton {
    
    private static Singleton mSingleton = new Singleton();

    public static Singleton getInstance() {
        return mSingleton;
    }
}

缺點:在類加載的時候就完成了初始化,所以類加載比較慢

  • 懶漢式
public class Singleton {

    private static Singleton mSingleton;

    public static Singleton getInstance() {
        if (mSingleton == null) {
            mSingleton = new Singleton();
        }
        return mSingleton;
    }
}

缺點:在多線程情況上不能正常工作

  • 雙重檢查鎖定(double-checked locking)
public class Singleton {

    private static Singleton mSingleton;

    public static Singleton getInstance() {

        if (mSingleton == null) {
            synchronized (Singleton.class) {
                if (mSingleton == null) {
                    mSingleton = new Singleton();
                }
            }
        }
        return mSingleton;
    }
}

缺點:在多線程運行的時候,mSingleton可能報空指針的錯誤。假設線程A運行getInstance()方法,當運行 mSingleton = new Singleton()的時候,線程B也調用getInstance()方法,因為mSingleton !=null(但實際上初始化有問題),直接返回mSingleton ,導致空指針問題。WTF?
??這是因為 mSingleton = new Singleton()這一步操作不是原子性操作(所謂原子操作是指不會被線程調度機制打斷的操作;這種操作一旦開始,就一直運行到結束,中間不會有任何 context switch ),在執行的過程中,需要3步處理1.mSingleton 分配內存 2.mSingleton 調用起構造函數 3.對mSingleton 指向內存分配區域 1--2--3,但有點時候jvm會將其重排序,可能1--3--2,在線程B調用的時候,雖然mSingleton 不是null,但它可能沒有進行初始化,導致空指針。

  • volatile關鍵字
    ?volatile能解決上面這種問題
    private  volatile static Singleton mSingleton;

mSingleton現在由volatile 關鍵字修飾,禁止重排序并且保證了變量的可見性。

  • 靜態內部類
public class Singleton {

    public static Singleton getInstance() {
        return Holder.mSingleton;
    }

    private static class Holder {
        private static Singleton mSingleton = new Singleton();
    }

}

??內部類分為對象級別和類級別,類級內部類指的是:有static修飾的成員變量的內部類。如果沒有static修飾的成員變量的內部類成為對象級內部類。
??類級內部類相當于外部類static成員,不存在依賴關系,相互獨立,只有在第一次使用時才會被初始化。
??當調用getInstance() 方法時,內部類Holder類才得到初始化;Singleton實例屬于靜態的域,由虛擬機來保證它的線程安全。
??這個模式優勢在于,getInstance()方法并沒有被同步,只是執行一個域的訪問,因為延時初始化并沒有增加任何訪問成本。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容