前言
本文是對《Adroid 源碼設(shè)計模式解析與實戰(zhàn)》 何紅輝缕陕、關(guān)愛民 著 人民郵電出版社所做的讀書筆記。文章是對本書的一些列學(xué)習(xí)筆記疙挺,如若有侵犯到作者權(quán)益扛邑,還望作者能聯(lián)系我,我會及時下架铐然。
這本書不錯蔬崩,有興趣的同學(xué)可以買原書看看。
感興趣的朋友歡迎加入學(xué)習(xí)小組QQ群: 193765960搀暑。
版權(quán)歸作者所有沥阳,如有轉(zhuǎn)發(fā),請注明文章出處:https://xiaodanchen.github.io/archives/
相關(guān)文章:
Android 設(shè)計模式:(一)面向?qū)ο蟮牧笤瓌t
Android 設(shè)計模式:(二)單例模式
Android 設(shè)計模式:(三)Builder模式
Android 設(shè)計模式:(四)原型模式
Android 設(shè)計模式:(五)工廠方法模式
Android 設(shè)計模式:(六)抽象工廠模式
Android 設(shè)計模式:(七)策略模式
1. 單例模式的定義
單例模式:確保某一個類只有一個實例险掀,而且自行實例化并向整個系統(tǒng)提供這個實例沪袭。
2. 單例模式的實現(xiàn)
在正式介紹單例模式之前,我們有必要了解一下 instance = new Singleton()這樣一條語句樟氢。乍一看這是一天簡單的語句冈绊,用來生成一個Singleton類的實例,但實際上他不是一條原子操作埠啃。這條代碼最終會被編譯成多條匯編指令死宣,他大致做了3件事情:
(1)給Singleton實例分配內(nèi)存。
(2)調(diào)用Singleton()構(gòu)造方法碴开,初始化成員字段毅该。
(3)將instance對象指向分配的內(nèi)存空間(此時instance就不是null了)博秫。
另外,JVM執(zhí)行上面三條匯編指令的順序是不定的眶掌,有可能是1-2-3挡育,也有可能是1-3-2。
2.1餓漢模式
代碼示例
public class Singleton{
private static final Singleton instance = new Singleton();
private Singleton(){}
public static Singleton getInstance(){
return instance;
}
}
優(yōu)缺點
優(yōu)點:
- 線程安全朴爬,無需關(guān)注多線程的問題即寒。
- 加載沒有延時:在類創(chuàng)建的同時,就已經(jīng)創(chuàng)建好類的實例
- 寫法簡單
缺點:
- 由于在類創(chuàng)建的時候召噩,就創(chuàng)建了實例(不管你會不會用到)母赵,那么就有可能會緩存很多用戶根本用不到的實例。
- 如果類中的實例會消耗較大量的內(nèi)存具滴,則要慎用餓漢模式創(chuàng)建單例凹嘲。
2.2 懶漢模式
代碼示例
public class Singleton{
private static Singleton instance;
private Singleton(){}
public static synchronized Singleton getInstance(){
if(null == instance){
intance = new Singleton();
}
return instance;
}
}
優(yōu)缺點
優(yōu)點:
- 在使用時才會創(chuàng)建實例,在一定程度上節(jié)省了資源构韵。
缺點: - 第一次加載時需要實例化周蹭,反應(yīng)稍慢。
- 加了同步鎖贞绳,造成不必要的同步開銷谷醉。
- 如果忘記加同步鎖,則是線程不安全的冈闭。
2.3 Double Check Lock
代碼示例
public class Singleton{
/**
* volatile:
* 告訴JVM不要對volitile所修飾的變量進行拷貝。
* 這樣就保證了instance不會在線程內(nèi)存中保存拷貝抖单,instance每次都從主內(nèi)存中讀取萎攒。
*
*/
private volatile static Singleton instance;
private Singleton(){}
public static Singleton getInstance(){
if(null == instance){
synchornized(Singleton.class){
if(null == instance){
intance = new Singleton();
}
}
}
return instance;
}
}
優(yōu)缺點
優(yōu)點:
- 資源利用率高,只有在第一次調(diào)用時才會分配資源矛绘。
- 相較于懶漢模式耍休,加載速度更快。
- 在一定程度上避免了多余的同步货矮,減輕了線程安全的問題羊精。
缺點:
- 第一次加載時存在延時,反應(yīng)較慢囚玫。
- 存在失效的情況(雖然概率較行酢):正如上文所說,如果當(dāng)前線程調(diào)用new Singleton()對應(yīng)的匯編的執(zhí)行順序是1-3-2抓督,當(dāng)有新的線程調(diào)用getinstance()時燃少,instance沒有初始化卻非空,就造成了instance失效铃在。
2.4 靜態(tài)內(nèi)部類單例模式
代碼示例
public class Singleton{
private Singleton(){}
public static Singleton getInstance(){
return SingletonHolder.instance;
}
/**
* 靜態(tài)內(nèi)部類
*/
private static class SinletonHolder{
private static final Singleton instace = new Singleton();
}
}
優(yōu)缺點
第一次加載Singleton類時并不會初始化instance阵具,只有在第一次調(diào)用Singleton的getInstace()方法時才會導(dǎo)致instance初始化碍遍。因為,第一次調(diào)用getInstace()時阳液,JVM才會加載SingletonHolder類怕敬。
這種方式不僅能夠確保線程的安全,而且延遲了實例化帘皿,避免了餓漢模式的資源浪費东跪,同時也能夠保證單例對象的唯一性。
2.5 枚舉單例
代碼示例
public enum SingletonEnum{
INSTANCE;
public void doSomething(){
...
}
}
優(yōu)缺點
- 寫法簡單
- 線程安全
- 在任何情況下(即使反序列化)矮烹,他都是一個實例越庇。2.1到2.4介紹的幾種方法,在反序列化(將實例對象寫入磁盤再讀取出來)時無法保證實例的唯一性奉狈。因為反序列化時系統(tǒng)會通過特殊的途徑創(chuàng)建一個類的新實例卤唉,相當(dāng)于調(diào)用了該類的構(gòu)造函數(shù),哪怕構(gòu)造函數(shù)是私有的仁期。反序列化操作提供了一個特別的鉤子函數(shù)readResolve()桑驱,這個方法可以讓開發(fā)人員控制對象的發(fā)序列化。例如跛蛋,上述幾個實現(xiàn)單例模式的方法要想杜絕反序列化時重新生成對象熬的,那么必須加入如下方法:
private Object readResolve() throw ObjectStreamException{
return instance;
}
2.6 使用容器實現(xiàn)單例
代碼示例
public class SingletonManager{
private static Map<String,Object> objMap = new HashMap<String,Object>();
private SingletonManager(){}
public static void registerService(String key, Object instance){
if(!objMap.containsKey(key)){
objMap.put(key,instance);
}
}
public static Object getService(String key){
return objMap.get(key);
}
}
優(yōu)缺點
在程序的初始,將多中單例類型注入到一個統(tǒng)一的管理類中赊级,在使用時根據(jù)key獲取對應(yīng)類型的對象押框。這種方式使得我們可以管理多種類型的單例,并且在使用時可以通過統(tǒng)一的接口進行獲取操作理逊,降低了用戶的使用成本橡伞,也對用戶隱藏了具體實現(xiàn),降低了耦合度晋被。
例如系統(tǒng)服務(wù)兑徘,就是這種模式:getSystemService(System.xx_SERVICE)