設計模式之建立型(1)——單例模式
阿新 • • 發佈:2019-01-13
定義:保證一個類僅有一個例項,並提供一個訪問它的全域性訪問點。
三種寫法:
(1)懶漢式
public class SingletonLazy { private static SingletonLazy instance = null; private SingletonLazy () {} public static SingletonLazy getInstance() { if (instance == null) { instance = new SingletonLazy(); } return instance; } }
優點:使用時才建立,節約資源
缺點: 執行緒不安全,因為多執行緒環境下,new SingletonLazy()可能會執行多次。
改進1:給getInstance()方法加鎖。
public class SingletonLazy { private static SingletonLazy instance = null; private SingletonLazy () {} public synchronized static SingletonLazy getInstance() { if (instance == null) { instance = new SingletonLazy(); } return instance; } }
問題:多執行緒環境下,雖然能保證單例,但是每個執行緒進入getInstance() 方法時,都會掛起其他的執行緒,即便SingletonLazy已經被例項化了,方法也不是立即返回,而synchronzized是有時間代價的,所以效率不高。
改進2:雙重檢查
public class SingletonDoubleCheck { private static SingletonDoubleCheck instance = null; private SingletonDoubleCheck () {} public static SingletonDoubleCheck getInstance() { if (instance == null) { synchronized (SingletonDoubleCheck.class) { if (instance == null) instance = new SingletonDoubleCheck(); } } return instance; } }
優點:多執行緒環境下
1. 執行getInstance()方法時,不需要阻塞,如果SingletonDoubleCheck已經被建立,則方法迅速返回物件例項。這是第一層檢查的的作用。
2. 只在SingletonDoubleCheck未被初始化的時候才加鎖,這是比“改進1”效率高的地方。第二層檢查的作用是保證單例。
問題:new SingletonDoubleCheck()不是一個“原子操作”,就是說這個操作需要n步才能完成,這裡涉及一個JVM的話題——指令重排序,這就可能導致先修改了instance的值,再執行真正的構造方法。所以,還是有可能出現一個執行緒未出這個語句塊時,另一個執行緒進入。(筆者對這個地方,還不太能解釋清楚,先做個標記,後面完善)
改進3:加volatile
public class SingletonDoubleCheck {
private volatile static SingletonDoubleCheck instance = null;
private SingletonDoubleCheck () {}
public static SingletonDoubleCheck getInstance() {
if (instance == null) {
synchronized (SingletonDoubleCheck.class) {
if (instance == null)
instance = new SingletonDoubleCheck();
}
}
return instance;
}
}
(2)餓漢式
public class SingletonHungry {
private static SingletonHungry instance = new SingletonHungry();
private SingletonHungry () {}
public static SingletonHungry getInstance() {
return instance;
}
}
優點:執行緒安全,由JVM load機制保證
缺點:過早浪費資源
(3) 靜態內部類式(推薦使用)
public class Singleton {
public static Singleton getInstance() {
return SingletonHolder.instance;
}
private Singleton() {}
private static class SingletonHolder {
private static Singleton instance = new Singleton();
}
}
優點:在使用時才建立例項物件,JVM機制。