更新時間:2021-09-30 來源:黑馬程序員 瀏覽量:
單例模式有很多實現方法,餓漢、懶漢、靜態內部類、枚舉類,試分析每種實現下獲取單例對象(即調用getInstance)時的線程安全,并思考注釋中的問題。
餓漢式:類加載就會導致該單實例對象被創建
懶漢式:類加載不會導致該單實例對象被創建,而是首次使用該對象時才會創建
1. 餓漢單例
// 問題1:為什么加 final // 問題2:如果實現了序列化接口, 還要做什么來防止反序列化破壞單例 public final class Singleton implements Serializable { // 問題3:為什么設置為私有? 是否能防止反射創建新的實例? private Singleton() {} // 問題4:這樣初始化是否能保證單例對象創建時的線程安全? private static final Singleton INSTANCE = new Singleton(); // 問題5:為什么提供靜態方法而不是直接將 INSTANCE 設置為 public, 說出你知道的理由 public static Singleton getInstance() { return INSTANCE; } public Object readResolve() { return INSTANCE; } }
2.枚舉單例
// 問題1:枚舉單例是如何限制實例個數的 // 問題2:枚舉單例在創建時是否有并發問題 // 問題3:枚舉單例能否被反射破壞單例 // 問題4:枚舉單例能否被反序列化破壞單例 // 問題5:枚舉單例屬于懶漢式還是餓漢式 // 問題6:枚舉單例如果希望加入一些單例創建時的初始化邏輯該如何做 enum Singleton { INSTANCE; }
3. 懶漢單例
public final class Singleton { private Singleton() { } private static Singleton INSTANCE = null; // 分析這里的線程安全, 并說明有什么缺點 public static synchronized Singleton getInstance() { if( INSTANCE != null ){ return INSTANCE; } INSTANCE = new Singleton(); return INSTANCE; } }
4. DCL 懶漢單例
public final class Singleton { private Singleton() { } // 問題1:解釋為什么要加 volatile ? private static volatile Singleton INSTANCE = null; // 問題2:對比實現3, 說出這樣做的意義 public static Singleton getInstance() { if (INSTANCE != null) { return INSTANCE; } synchronized (Singleton.class) { // 問題3:為什么還要在這里加為空判斷, 之前不是判斷過了嗎 if (INSTANCE != null) { // t2 return INSTANCE; } INSTANCE = new Singleton(); return INSTANCE; } } }
5. 靜態內部類懶漢單例
public final class Singleton { private Singleton() { } // 問題1:屬于懶漢式還是餓漢式 private static class LazyHolder { static final Singleton INSTANCE = new Singleton(); } // 問題2:在創建時是否有并發問題 public static Singleton getInstance() { return LazyHolder.INSTANCE; } }
猜你喜歡: