【設計模式】(四)--創建型模式--單例模式

單例模式的定義

Ensure a class has only one instance, and provide a global point of access to it.
確保一個類只有一個實例,能夠對整個系統提供訪問。

Java語言中實現單例通常有兩種變現形式。

  • 餓漢式單例模式:類加載時,就進行對象實例化
  • 懶漢式單例模式:第一次引用類才進行對象實例化

餓漢式單例模式

一種簡單的餓漢式單例模式如下
在這裏插入圖片描述

public class Singleton {
    private static Singleton _instance = new Singleton();

    private Singleton() {
    }

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

類加載時_instance會被初始化,此時private Singleton()【私有構造方法】會被調用,Singleton類的唯一實例創建成功。因爲私有構造方法,外界無法利用構造函數創建出實例。整個系統僅有一個Singleton類實例。因爲private Singleton(),因此類不能被繼承。

懶漢式單例模式

一種簡單的懶漢單例模式
在這裏插入圖片描述

public class Singleton {
    private static Singleton _instance = null;

    private Singleton() {

    }
    synchronized public static Singleton getInstance() {
        if (_instance == null) {
            _instance = new Singleton();
        }

        return _instance;
    }
}

外界調用Singleton 類靜態同步方式getInstance()方法,因爲進行了同步,即使併發也僅會產生一個實例。

餓漢式與懶漢式的區別:

餓漢式 懶漢式
實例化階段 類加載時實例化 第一次引用時實例化
資源利用效率
速度和反應時間

單例模式的優點

  1. 內存中僅有一個實例,節約資源。
  2. 不用頻繁的創建和銷燬對象,提高性能。
  3. 僅有一個實例形成全局唯一的訪問點。
  4. 避免對資源的多重佔用。

單例模式的缺點

  1. 拓展困難,構造方法私有,無法繼承。
  2. 不利於測試,某些測試方式無法方便的創建單例實例來模擬測試
  3. 與單一職責原則衝突。(來給我拓展一下)

Java中其他生成單例的方式

使用Spring框架,Spring框架默認就是單例

雙重校驗鎖

性能比直接方法上加同步好。進行了兩次的判斷,第一次是爲了避免不必要進入同步塊,第二次是爲了進行同步,避免多線程問題。由於singleton=new Singleton()對象的創建在JVM中可能會進行重排序,在多線程訪問下存在風險,使用volatile修飾signleton實例變量有效,解決該問題。

public class Singleton {
    private volatile static Singleton _instance = null;
    private Singleton() {
    }
    public static Singleton getInstance() {
        if (_instance == null) {
            synchronized (Singleton.class) {
                if (_instance == null) {
                    _instance = new Singleton();
                }
            }
        }
        return _instance;
    }
}

靜態內部類

只有第一次調用getInstance方法時,虛擬機才加載 Inner 並初始化instance ,只有一個線程可以獲得對象的初始化鎖,其他線程無法進行初始化,保證對象的唯一性。目前此方式是所有單例模式中最推薦的模式

public class Singleton {
    private static class SingletonHolder {
        private static final Singleton INSTANCE = new Singleton();
    }
    private Singleton() {
    }
    public static final Singleton getInstance() {
        return SingletonHolder.INSTANCE;
    }
}

枚舉

默認枚舉實例的創建是線程安全的,並且在任何情況下都是單例

public enum Singleton {
    INSTANCE;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章