1、定義
單例模式屬於創建型模式,確保一個類只有一個實例,並提供一個全局的訪問接口。
2、使用場景
在開發工程中,有些對象我們只需要一個:線程池、緩存、硬件設備等, 創建多個實例則會造成結果的不一致和資源的過多消耗。
3、UML類圖
4、經典的實現方式
1、懶漢模式
/**
* 懶漢模式
*/
public class SingleTon01 {
private static SingleTon01 instance;
private SingleTon01() {
}
public static synchronized SingleTon01 getInstance() {
if (instance == null) {
instance = new SingleTon01();
}
return instance;
}
}
懶漢模式在使用的時候才進行實例化,在一定程度上節約了資源,但是在每次調用getInstance()都進行了同步,造成不必要的同步。
2、Double Check Lock(DCL)模式
/**
* Double Check Lock(DCL)雙鎖檢測
*/
public class SingleTon02 {
private volatile static SingleTon02 instance;
/**
* 構造方法私有化,不允許外部創建對象
*/
private SingleTon02() {
}
public static SingleTon02 getInstance() {
if (instance == null) {//第一次判空避免不必要的同步
synchronized (SingleTon02.class) {
if (instance == null) {//第二次判空爲了在null的情況下創建實例
instance = new SingleTon02();
}
}
}
return instance;
}
}
DCL是使用最多的一種實現單例的方式,但在《Java併發編程實戰》中提到這是一種"糟糕"的優化,在java1.5以前的版本中並沒有真正解決線程同步問題,在1.5版本以後可以加上volatile3、靜態類部類模式
/**
* 靜態類部類模式
*/
public class SingleTon03 {
private SingleTon03() {
}
private static class SingletonHolder {
private static final SingleTon03 instance = new SingleTon03();
}
public static SingleTon03 getInstance() {
return SingletonHolder.instance;
}
}
這種方式不僅能夠保證線程安全,同時也能夠保證單例對象的唯一性,延遲單例對象的實例化。4、枚舉實現單例
/**
* 枚舉單例
*/
public enum SingleTon04 {
INSTANCE;
}
枚舉對象的創建是現成安全的,並且也是唯一的。5、利用容器實現單例
/**
* 利用容器實現單例
*/
public class SingleTon05 {
private static Map<String, Object> objMap = new HashMap<>();
private SingleTon05() {}
public void addObj(String key, Object instance) {
if (!objMap.containsKey(key)) {
objMap.put(key, instance);
}
}
public static Object getObj(String key) {
return objMap.get(key);
}
}
我們可以通過這種方式管理多種類型的管理,如對activity的管理。
5、總結
優點:1、全局只有一個實例,減小了系統性能開銷。
缺點:1、擴展困難,只能通過修改代碼的方式進行擴展。
2、如果單例持有Context對象,容易造成內存泄漏問題,一般傳遞Application對象。
代碼:https://gitee.com/os2chen/DesignPattern
參考:《Head First Design》、《Android源碼設計模式解析與實戰》