本文主要根據(jù)以下著作中的內(nèi)容整理而來:
何紅輝,關(guān)愛民.Android源碼設(shè)計模式解析與實踐第2版〔M〕.北京:人民郵電出版社棱诱,2017.7
定義
確保某一個類只有一個實例疗绣,自行實例化并向整個系統(tǒng)提供這個實例烙懦。
角色
Client——高層客戶端踪区。
Singleton——單例類。
特點
私有:構(gòu)造方法是私有的吊骤,靜態(tài)變量是私有的缎岗。
靜態(tài):通過一個公有的靜態(tài)方法或枚舉返回單例類對象。
線程安全:多線程環(huán)境下也要確保對象只有一個白粉。
幾種實現(xiàn)方式
以下幾種方式在初始化靜態(tài)對象上有不同传泊。
餓漢模式:聲明靜態(tài)對象時直接初始化鼠渺。new的過程很耗時的話,應(yīng)用程序啟動的會很慢眷细,降低體驗的友好性
懶漢模式:聲明一個靜態(tài)對象拦盹,在用戶第一次調(diào)用getInstance()時初始化。延遲單例的實例化溪椎。
? ? ? ? ? ? ? ??懶漢模式 問題:getInstance的調(diào)用頻率很高的話普舆,每次都synchronized同步訪問,效率低校读。
雙重檢查鎖定(DCL):既能在需要時初始化沼侣,又能保證線程安全,消除懶漢模式中重復(fù)同步問題歉秫。(得比較多的方式蛾洛,JDK1.5及以上版本使用volatile,沒有復(fù)雜的并發(fā)場景下一般能滿足使用)
靜態(tài)內(nèi)部類:解決雙重檢查鎖定失效問題雁芙。(推薦使用的實現(xiàn)方式)
代碼示例
雙重檢查鎖定方式:
public class Singleton{
? ? //問題1:new操作的反匯編代碼轧膘,其實他包含3條匯編指令:new、dup兔甘、init谎碍。sInstance 不為null并不保證sInstance是完整地初始化好了成員。
? ? // 問題2:即使一個線程實例化了sInstance 裂明,由于每個線程都有自己的working緩存椿浓,可能另一個線程看不到前一個線程對sInstance 的操作。
? ? // JDK1.5及以后 使用volatile關(guān)鍵字闽晦,保證每次sInstance都是從主內(nèi)存中獲取扳碍。
? ? private volatile static Single sInstance = null;
? ? private Singleton(){}
? ? public static Singleton getInstance(){
? ? ? ? if(sInstance==null){
? ? ? ? ? ? synchronize(Singleton.class){
? ? ? ? ? ? ? ? if(sInstance==null){
? ? ? ? ? ? ? ? ? ? ?? sInstance = new Singleton();//實際上不是一個原子操作:1.給Singleton實例分配內(nèi)存;2.調(diào)用Singleton()構(gòu)造方法初始化成員字段仙蛉;3.將sInstance指向分配的內(nèi)存空間笋敞。 執(zhí)行順序可能是1-2-3或者1-2-3。
????????????????}
????????????}
????????}
????}
}
靜態(tài)內(nèi)部類方式:
public class Singleton{
? ? private?Singleton(){}
????public static?Singleton getInstance(){
? ? ? ? // 延遲初始化
? ? ? ? return SingletonHolder.sInstance;
????}
?? private static class SingletonHolder{
? ? ? ? //靜態(tài)變量是線程共享的荠瘪,保證了單例的線程安全躏救。避免了雙重檢查鎖定失效問題吱瘩。
? ? ? ? private static final Singleton sInstance = new?Singleton();
????}
}
擴展應(yīng)用
使用容器實現(xiàn)單例
Android Context的實現(xiàn)類ContextImpl
public class ContextImpl extends Context {
? ? private final static Map<String,ServiceFetcher> SYSTEM_SERVICE_MAP= new HashMap<String,ServiceFetcher>();
? ? public static void registerService(String serviceName,ServiceFetcher fetcher){
? ? ? ? //省略代碼
????????SYSTEM_SERVICE_MAP.put(serviceName,fetcher);
????}
? ? public Object getSystemService(String key){
? ? ? ? ServiceFetcher fetcher =?SYSTEM_SERVICE_MAP.get(key);
? ? ? ? return fetcher ==null? null:fetcher.getService(this)
????}
? ? static {
? ? ? ? registerService(LAYOUT_INFLATER_SERVICE,new ServiceFetcher(){
? ? ? ? ? ? public Object createService(ContextImpl ctx){
? ? ? ? ? ? ? ? return PolicyManager.makeNewLayoutInflater(ctx.getOuterContext());
????????????}
????????})
????}
}