java設計模式之單例模式你真的會了嗎?(懶漢式篇)

野生D程式猿發表於2021-05-18

java設計模式之單例模式你真的會了嗎?(懶漢式篇)

一、什麼是單例模式?

單例模式(Singleton Pattern)是 Java 中最簡單的設計模式之一。這種型別的設計模式屬於建立型模式,它提供了一種建立物件的最佳方式。
這種模式涉及到一個單一的類,該類負責建立自己的物件,同時確保只有單個物件被建立。這個類提供了一種訪問其唯一的物件的方式,可以直接訪問,不需要例項化該類的物件。

二、單例模式之懶漢式有什麼特點以及優缺點?

  • 構造方法私有化
  • 在第一次被使用時構建例項,延遲初始化
  • 對外提供統一的靜態工廠方法返回例項
  • 優點:需要的時候才例項化所以節約記憶體。
  • 缺點:第一次載入時不夠快,多執行緒使用時不必要的同步開銷大。

三、懶漢式單例的程式碼進階(1)

public class LazySingleton implements Serializable {
    private static final long serialVersionUID = -777413485350310911L;

    private LazySingleton() {}

    private static LazySingleton lazySingleton = null;

    public static LazySingleton getInstance() {
        if(lazySingleton == null){
            lazySingleton = new LazySingleton();
        }
        return lazySingleton;
    }
}
  • 上面的程式碼存在著最明顯的問題就是在多執行緒的環境下無法保證單例。

四、懶漢式單例的程式碼進階(2)

public class LazySingleton implements Serializable {
    private static final long serialVersionUID = -777413485350310911L;

    private LazySingleton() {}

    private static LazySingleton lazySingleton = null;

    synchronized public static LazySingleton getInstance() {
        if(lazySingleton == null){
            lazySingleton = new LazySingleton();
        }
        return lazySingleton;
    }
}
  • 上面的程式碼在getInstance()方法前面增加了關鍵字synchronized進行執行緒鎖,以處理多個執行緒同時訪問的問題。但是,這樣雖然解決了執行緒安全問題,但是每次呼叫getInstance()時都需要進行執行緒鎖定判斷,在多執行緒高併發訪問環境中,將會導致系統效能大大降低。

五、懶漢式單例的程式碼進階(3)

public class LazySingleton implements Serializable {
    private static final long serialVersionUID = -777413485350310911L;

    private LazySingleton() {}

    private static LazySingleton lazySingleton = null;

    //double check
    public static LazySingleton getInstance() {
        if(lazySingleton == null){
            synchronized(LazySingleton.class){
                if(lazySingleton == null){
                    lazySingleton = new LazySingleton();
                }
            }
        }
        return lazySingleton;
    }
}
  • 上面的程式碼採用synchronized和double check的方式成功解決了執行緒安全問題以及提高了多執行緒下的效能,但是效能任然不夠理想。

六、懶漢式單例的程式碼進階(4)

public class LazySingleton implements Serializable {
    private static final long serialVersionUID = -777413485350310911L;

    private LazySingleton() {}

    public static LazySingleton getInstance() {
        return LazyInnerSingleton.INSTANCE;
    }

    /**
     * 利用內部類的特性建立單例
     */
    private static class LazyInnerSingleton {
        private static final LazySingleton INSTANCE = new LazySingleton();
    }
}
  • 上面利用內部類的特性建立單例既保證了執行緒安全(由jvm的類載入機制提供)問題又提高了效能,但是還是存在著一個問題:利用反射依然可以破壞“單例”,所以繼續改進程式碼。

六、懶漢式單例的程式碼進階(5)

public class LazySingleton implements Serializable {
    private static final long serialVersionUID = -777413485350310911L;

    private LazySingleton() {
        //防止利用反射破壞單例
        if(LazyInnerSingleton.INSTANCE != null){
            throw new RuntimeException("不允許構建多個例項!");
        }
    }

    public static LazySingleton getInstance() {
        return LazyInnerSingleton.INSTANCE;
    }

    /**
     * 利用內部類的特性建立單例
     */
    private static class LazyInnerSingleton {
        private static final LazySingleton INSTANCE = new LazySingleton();
    }
}
  • 在構造方法中丟擲一個異常以防止通過反射破壞單例。

PS:如果你看到了這篇文章,並且覺得對你有幫助,請給個關注和點贊,謝謝!

相關文章