一、有什么用
保證應用程序中只有該類的一個實例
二、特點
好的單例模式應保證:1)線程安全;2)延遲加載:真正使用的時候才去創(chuàng)建實例,不用的時候不創(chuàng)建;3)類的構造函數(shù)一般用 private 修飾,不對外公開。
三、可用的幾種單例實現(xiàn)
1.餓漢
/**
*
* <p>
* Description: 餓漢模式
* 優(yōu)點:線程安全
* 缺點:無延時加載(過早的創(chuàng)建實例,降低內存使用率)
* </p>
*
* @author 楊麗金
* @date 2018-4-8
* @version 1.0
*/
public class Singleton4 {
private Singleton4() {}
/**
* 類的初始化階段即為執(zhí)行<clinit>方法的階段。
* 聲明靜態(tài)變量時的初始化操作+static初始化塊中語句=>被合并到<clinit>方法中。
* JVM保證執(zhí)行<clinit>方法時:該方法可被正確的加鎖、同步,保證了Singleton4對象創(chuàng)建時的線程安全
* 故:JVM可保證只創(chuàng)建該類的一個實例
*/
private static Singleton4 instance=new Singleton4();
/**
* 當類的靜態(tài)方法被調用時,初始化類(當然之前要完成加載、驗證、準備)
* @return
*/
public static Singleton4 getInstance() {
return instance;
}
}
2. 懶漢模式
public class Singleton {
private Singleton(){}
private static Singleton instance;
public static synchronized Singleton getInstance() {
if (instance == null) {
instance=new Singleton();
}
return instance;
}
}
該方法可保證實例的唯一性,不足之處是:第一次初始化后,再獲取實例還要進行同步操作,造成不必須的系統(tǒng)開銷。
3.雙重檢查鎖定單例模式
優(yōu)點:線程安全;延遲加載
缺點:代碼復雜,容易出錯
特點:1,volatile修飾;2,雙重檢查
/**
*
* <p>
* Description: 懶漢模式
* 缺點:代碼復雜,容易出錯
* </p>
*
* @author 楊麗金
* @date 2018-4-8
* @version 1.0
*/
public class Singleton3 {
private Singleton3() {
}
/**
* 這里要用volatile:防止new Singleton3()操作的指令重排序導致的錯誤
* (JDK1.5以后這種錯誤才因volatile的出現(xiàn)得以避免;JDK1.5之前,毛的辦法)
*/
private volatile static Singleton3 instance = null;
public static Singleton3 getInstance() {
// 這樣的好處是:在實例還未創(chuàng)建時需要加鎖,創(chuàng)建以后則不需加鎖了
if(instance==null){
synchronized(Singleton3.class){
if (instance == null) {
instance = new Singleton3();
}
}
}
return instance;
}
}
注意instance = new Singleton();這行代碼,它的執(zhí)行可以分解為第三個步驟:(1)為instance實例分配內存。(2)執(zhí)行Singleton構造函數(shù)來初始化instance。(3)將instance指向分配的內存。
但在JDK1.5前,上邊的(2)(3)無法保證按順序執(zhí)行,如果按(1)(3)(2)順序,假如A線程執(zhí)行完(3),(2)未執(zhí)行就被切換到B線程,因為步驟(3)已經(jīng)在A線程執(zhí)行,則B線程直接取走了認為非空instance,這就導致雙重檢查鎖定的判斷失效。
4.靜態(tài)內部類單例模式
優(yōu)點:線程安全;延遲加載
缺點:無
特點:由于在讀取實例的時候不會進行同步,所以沒有性能缺陷;沒有使用 volatile ,也不依賴 JDK 版本
/**
*
* <p>
* Description: 靜態(tài)內部類單例模式
* 優(yōu)點:線程安全,懶加載
* 缺點:無明顯缺點
* </p>
*
* @author 楊麗金
* @date 2018-4-8
* @version 1.0
*/
public class Singleton5 {
private Singleton5() {
}
/**
* 當類的靜態(tài)方法被調用時,初始化類(當然之前要完成加載、驗證、準備)
* @return
*/
public static Singleton5 getInstance() {
/**
* 當獲取SingletonHolder的靜態(tài)變量的值時,SingletonHolder類被初始化,
* 其中創(chuàng)建Singleton對象的操作在SingletonHolder的<clinit>方法中,
* 由JVM加鎖同步,保證線程安全
*/
return SingletonHolder.instance;
}
/**
* 當類Singleton5被初始化時不會加載初始化SingletonHolder,這樣達到了懶加載的效果
*/
private static class SingletonHolder{
/*這里的私有沒有什么意義
private*/ static Singleton5 instance=new Singleton5();
}
}
參考文獻
小小芳_單例模式
【單例深思】靜態(tài)內部類實現(xiàn)詳解
【單例深思】餓漢式與類加載
設計模式
SheHuan_單例模式