單例設計模式是應用最廣的,它必須保證一個實例,例如一個ImageLoader實例,自行實例化并且向整個系統(tǒng)提供這個實例。
當創(chuàng)建一個對象的時候消耗過多,例如要訪問IO、數(shù)據(jù)庫資源等時使用。
特點
1.構(gòu)造函數(shù)不對外開放,private。
2.通過一個靜態(tài)方法或者枚舉返回單例類對象。
3.確保單例對象只有一個,特別是多線程。
4.確保在反序列化時不會重新構(gòu)建對象
分為兩種:
餓漢:類一創(chuàng)建就new對象出來。
懶漢:使用時候才去通過判斷對象是否為null來new新對象。
為了保證對象唯一,有幾種實現(xiàn)方法:
1.懶漢DCL(DoubleCheckLock)(一般能滿足需求)
雙重校驗同步代碼塊方法去new對象。
缺點:
高并發(fā)下,由于不是原子操作,可能會失效,
java5以后,可以在成員變量上加上volatile來禁止該對象上的讀寫指令重排序。
2.靜態(tài)內(nèi)部類單例模式: 推薦
3.枚舉單例 避免發(fā)序列化產(chǎn)生對象另類:容器實現(xiàn)單例模式
缺點:
接口擴展困難,
如果傳入的是Activity的context 很可能內(nèi)存泄露
4.使用容器來實現(xiàn)單例。
android源碼中的單例模式:
?我們常常通過context來獲取系統(tǒng)級別的服務,如WindowsManagerService、ActivityManagerService等,跟常用的是LayoutInflater類。
下面來分析下LayoutInflater
LayoutInflater.form(context)獲取單例->點進去也是調(diào)用了context.getSystemService(context.LAYOUT_INFLATER_SERVICE)
我們知道Activity對象和Context對象是在ActivityThread的main函數(shù)中生成的,找到main函數(shù)發(fā)現(xiàn)context是ComtextImpl.createActivityContext(this,r.pakageInfo,t.token)生成,然后通過activity.Attach傳入Activity中的。
最后來看ComtextImpl類
這里使用的使用容器實現(xiàn)單例模式。
容器:private static final HashMap<String,ServiceFetcher> SYSTEM_SERVICE_MAP = new ...;
//在ComtextImpl類static代碼塊中,會生成各種ServiceFatcher,然后存入SYSTEM_SERVICE_MAP中。
ComtextImpl類有一個getSystemService(String name)方法用來獲取存入SYSTEM_SERVICE_MAP中的ServiceFatcher對象,然后調(diào)用fetcher.getServiece(comtextImpl)方法。
fetcher中的getServiece方法從緩存ctxImpl.mServiceCache中獲取對象cache.get(mContextCacheIndex)避免重復創(chuàng)建。
我們?nèi)绾芜\用單例模式
例子:
ImageLoader使用DCL(Double checkLock)的方式來獲取對象
public static InmageLoadegetInstance(){
?if(sInstance ==null){
? ? synchronized(ImageLoader.class){
? ? ? i f(sInstance ==null){
? ? ? ? sInstance = new ImageLoader();
? ? ? }
? ? }
? }
}