【設計模式】(四)--創建型模式--單例模式
單例模式的定義
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()方法,因爲進行了同步,即使併發也僅會產生一個實例。
餓漢式與懶漢式的區別:
餓漢式 | 懶漢式 | |
---|---|---|
實例化階段 | 類加載時實例化 | 第一次引用時實例化 |
資源利用效率 | √ | |
速度和反應時間 | √ |
單例模式的優點
- 內存中僅有一個實例,節約資源。
- 不用頻繁的創建和銷燬對象,提高性能。
- 僅有一個實例形成全局唯一的訪問點。
- 避免對資源的多重佔用。
單例模式的缺點
- 拓展困難,構造方法私有,無法繼承。
- 不利於測試,某些測試方式無法方便的創建單例實例來模擬測試
- 與單一職責原則衝突。(來給我拓展一下)
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;
}