談談部分單例設計模式

餓漢模式

public class Singleton1 implements Serializable {
    private static Singleton1 instance = new Singleton1();
    private Singleton1(){

    }
    public static Singleton1 getInstance(){
        return instance;
    }
}

是怎麼保證線程安全的?

線程安全的懶漢模式

雙重檢測鎖(Double Checked Lock DCL) + volatitle

  • DCL,避免多個線程同時指執行到if(instance == null),判斷都爲true,會排隊創新等待創建新對象
  • volatitle關鍵字 防止CPU指令重排,instance = new Singleton4()不是原子操作,會涉及三個步驟,CPU執行順序有可能會亂(給實例分配內存空間;調用對象的構造方法,初始化成員字段;將instance 對象指向分配的內存空間)
public class Singleton4 {
    private volatile static Singleton4 instance;
    private Singleton4(){}
    public static Singleton4 getInstance(){
        if(instance == null){
            synchronized (Singleton4.class){
                if(instance == null){
                    instance = new Singleton4();
                }
            }
        }
        return instance;
    }
}

在第一次調用Singleton4.getInstance()的時候初始化靜態變量
類並不是在加載完之後就會實例static變量。那到底什麼時候纔會初始化呢?

1.當遇到new,getstatic,putstatic或者invokestatic這四條字節碼指令的時候,如果該類沒有進行
初始化,則需要先初始化.這四條指令對應的是實例化對象,獲取一個靜態變量,設置一個靜態變量(常量
放在常量池中,不會觸發),或者調用靜態方法的時候.
2.當時候反射包的方法對類進行反射調用的時候
3.當初始化一個類的時候,發現該類的父類還沒有進行初始化,則初始其父類
4.當jvm啓動的時候,當用戶指定執行一個主類(就是包含main的那個類),虛擬機會先初始化這個類.

上述的例子是因爲滿足第一條,執行static方法的時候編譯器會生成invokestatic指令,這時候instance沒有初始化,所以會執行Instance的構造方法,然後在return返回。

靜態內部類模式

public class Instance1 {
    private static class Holder{
        private static Instance1 instance = new Instance1();
    }
    private Instance1(){
        System.out.println("instance1 alloc");
    }
    public static Instance1 getInstance(){
        System.out.println("instance1 called");
      
        return instance;
    }
}

靜態內部類和餓漢模式都採用類裝載的機制保證,當初始化實例的時候只有一個線程執行,保證了多線程下的安全。
JVM會在類初始化的階段(類裝載的階段)創建一個鎖,該鎖保證多個線程同步執行類初始化的工作,因此在多線程環境下,類加載的機制依然是安全的。
餓漢模式 是啓動就加載,造成資源浪費
靜態內部類 只有在調用getInstance方法的時候 纔會去裝載內部類,從而完成實例的初始化,不造成資源的浪費。 爲比較推薦的單例實現方式。

參考

  1. https://blog.csdn.net/y1962475006/article/details/79035250
  2. https://blog.csdn.net/y1962475006/article/details/102642440
  3. 深入理解Javax虛擬機-7.3.5初始化
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章