定義:確保一個類只有一個實列。
單列模式有幾個要點:
1、定義一個私有的構(gòu)造函數(shù)
2粘茄、一個私有的變量
3、公開的靜態(tài)的獲取實例的方法
4秕脓、確保多線程下實例化對象只有一個
將構(gòu)造方法私有化柒瓣,使得客戶端不能通過new的形式來獲取實例。單列會暴露一個獲取實例的靜態(tài)的方法獲取唯一的對象吠架。獲取單列需要線程安全芙贫,尤其是在多線程的環(huán)境下。
通常是用于該類需要消耗較多的資源或者沒有多個實例的情況傍药。
public class Singleton {
//私有的成員變量
private static Singleton mSingleton = new Singleton();
//私有的構(gòu)造放啊發(fā)
private Singleton(){}
//對外公開獲取實例的方法
public static Singleton getInstance() {
return mSingleton;
}
}
DCL方式實現(xiàn)單例
public class Singleton {
private volatile static Singleton sInstance = null;
private Singleton(){}
public static Singleton getInstance() {
if (sInstance != null) {
synchronized (Singleton.class) {
if (sInstance != null){
sInstance = new Singleton();
}
}
}
return sInstance;
}
}
在獲取實例的時候進行了兩次判空磺平,為什么這么做呢,因為sInstance = new Singleton();這里看起來是一句代碼拐辽,但實際上并不是一個原子操作拣挪,這句這句代碼最終會被編譯成多條匯編指令,它大致做了三件事情:
1俱诸、給Sington實例分配內(nèi)存
2菠劝、調(diào)用Sington的構(gòu)造函數(shù),初始化成員
3乙埃、將sInstance引用執(zhí)行Sington的內(nèi)存地址
但是由于java編譯器是亂序執(zhí)行的闸英,第二第三步驟無法保證執(zhí)行順序,如果執(zhí)行的是3-2介袜,當這個線程執(zhí)行完成3之后甫何,另一個線程來取,但是這時候還未執(zhí)行2步驟遇伞,如果另個線程使用這個還未實例化的對象就會出現(xiàn)DCL(Double Check Lock)失效辙喂,所以加上volatitle關(guān)鍵字(用volatile修飾的變量,線程在每次使用變量的時候鸠珠,都會讀取變量修改后的最的值)巍耗,保證每次從內(nèi)存取。
- 靜態(tài)內(nèi)部類的方式
因為DCL單例模式會有一定概率早哼DCK失效渐排,所以不建議用這種方式炬太,而建議用下列方式:
public class Singleton {
private Singleton() {}
public static Singleton getInstance() {
return SingletonHolder.sInstance;
}
public static class SingletonHolder {
public static final Singleton sInstance = new Singleton();
}
}
這種方式只有在調(diào)用getInstance方法的時候才去初始化SingletonHolder類,既保證了單一實例有保證了延時加載驯耻,還保證了線程安全亲族。
- 優(yōu)點:
1、單例模式全局只有實例可缚,減少了系統(tǒng)開銷霎迫,特別是一個類需要頻繁的創(chuàng)建銷毀而無法進行內(nèi)存優(yōu)化的時候。優(yōu)勢就特別明顯帘靡。
2知给、單利模式為一個全局資源的訪問提供了便利。 - 缺點:單例模式可擴展性差描姚。
補充:這樣的單利模式是餓漢模式涩赢,與之對應(yīng)的是懶漢模式,還有通過靜態(tài)內(nèi)聚類創(chuàng)建實例的轰胁。