二學單例模式
哎呀!單例都學爛了,有什麼好學的啊?
因爲今天看《Head First 設計模式》看到了一些細節部分,決定重新認識一下單例
應用場景
- 線程池
- 緩存
- 註冊表
- 工廠
- 對話框
- 偏好設置
- …
普通的單例
我們先來看看
public Single{
private static Single singleInstance;
private Single(){}
public static Single getSingleInstance(){
if(singleInstance == null){
singleInstance = new Single();
}
return singleInstance;
}
}
很簡單的一個例子,大家都會寫,把構造隱藏起來,把方法暴露出去,blablabla…
但是這涉及到多線程的話,如果我兩個線程同時到達if(singleInstance == null)
,怎麼辦,這就會出來兩個不同的對象啊,這是不安全的,那怎麼辦呢?
線程安全性
處理多線程問題,我們有三種方法
方法一:提前new好
別嫌代碼臭嗷~
public Single{
private static Single singleInstance = new Single();
private Single(){}
public static Single getSingleInstance(){
return singleInstance;
}
}
JVM加載這個類時,馬上就會創建好這個對象。如果在創建和運行方面壓力不大,你又急着用,確實可以這麼做
方法二:增加同步(synchronized)塊
還記得synchronized
嗎?
public Single{
private static Single singleInstance;
private Single(){}
public static synchronized Single getSingleInstance(){
if(singleInstance == null){
singleInstance = new Single();
}
return singleInstance;
}
}
在方法中間加上synchronized
關鍵字,問題解決了,但如果我對象都已經創建好了了,我直接拿不久行了,也擱哪兒等着?所以,隨之而來的是性能的災難…(可能差幾十倍甚至一百倍)
方法三:減少同步,使用雙重鎖DCL(Double-Checked Lock)
先檢查單例對象創建了沒,沒創建再同步,而不是不管三七二十一,全同步了
public Single{
private volatile static Single singleInstance;
private Single(){}
public static Single getSingleInstance(){
if(singleInstance == null){
synchronized(Single.class){
if(singleInstance == null){
singleInstance = new Single();
}
}
}
return singleInstance;
}
}
利用雙重鎖機制,性能🆙
單例 vs 全局變量
還記得我“二學static”裏面的例子嗎?
//Code.1
public Single{
static public void FuncA(Object o);
static public void FuncB(Object o);
static public void FuncC(Object o);
}
// Code.2
public Single{
private static Single singleInstance;
private Single(){}
public static Single getSingleInstance(){
if(singleInstance == null){
singleInstance = new Single();
}
return singleInstance;
}
public void FuncA(Object o);
public void FuncB(Object o);
public void FuncC(Object o);
}
// 分別調用FuncA
Object o = new Object();
// call 1
Single.FuncA(o);
// call 2
Single.getSingleInstance().FuncA(o);
除了我之前文章說的不同,還存在初始化的和控制權不同的問題
初始化
- 單例延遲初始化
- 類加載後的初始化時間在Java程序
控制權
- 單例控制權在我們
- 全局變量控制權在Java