1、定義
單例對象的類必須保證只有一個實例存在。
確保某一個類只有一個實例,而且自行實例化并向整個系統(tǒng)提供這個實例。
2、使用場景
避免產(chǎn)生對個對象消耗過多的資源,或者某種類型的對象只應(yīng)該有且只有一個。
3、實現(xiàn)方式
- 餓漢模式
public class CEO {
private static final CEO mCEO = new CEO();
private CEO() {
}
public static CEO getCEO() {
return mCEO;
}
}
- 懶漢模式
public class CEO {
private static CEO instance;
private CEO() {
}
public synchronized static CEO getCEO() {
if (instance == null) {
instance = new CEO();
}
return instance;
}
}
- 懶漢模式 - double checkLock
public class CEO {
private CEO() {
}
private static CEO instance = null;
public static CEO getInstance() {
//避免不必要的同步
if (instance == null) {
synchronized (CEO.class) {
//同步后仍然為null,再創(chuàng)建
if (instance == null) {
instance = new CEO();
}
}
}
return instance;
}
}
- 靜態(tài)內(nèi)部類
public class CEO {
private CEO() {
}
public static CEO getInstance() {
return CEOHolder.instance;
}
/**
* 靜態(tài)內(nèi)部類
* 確保線程安全,也能保證單例對象的唯一性
* 延時了單例的初始化
*/
private static class CEOHolder {
private static final CEO instance = new CEO();
}
//防止反序列化時,可以通過反射來創(chuàng)建新對象
private Object readResolve() throws ObjectStreamException {
return getInstance();
}
}
- 枚舉
默認枚舉實例的創(chuàng)建是線程安全的,并且在任何情況下它都是一個單例,包括反序列化的時候(其余的實現(xiàn)都會在反序列化時出現(xiàn)問題,靜態(tài)內(nèi)部類實現(xiàn)方式已給出解決方案 反序列化相關(guān))
public enum CEO {
INSTANCE;
}
- 容器
通過統(tǒng)一的接口進行獲取操作,降低了使用成本,及耦合度
public class SingletonManager {
private static Map<String, Object> sObjectMap = new HashMap<>();
private SingletonManager() {
}
public static void registerService(String key, Object instance) {
if (!sObjectMap.containsKey(key)) {
sObjectMap.put(key, instance);
}
}
public static Object getService(String key) {
return sObjectMap.get(key);
}
}
4、Demo
5、Android 源碼中的運用
android.content.Context
public final @Nullable <T> T getSystemService(@NonNull Class<T> serviceClass)
優(yōu)缺點
- 優(yōu)點
- 減少了內(nèi)存開支
- 減少了系統(tǒng)的性能開銷
- 避免對資源的多重占用
- 可以在系統(tǒng)設(shè)置全局的訪問點,優(yōu)化和共享資源訪問
- 缺點
- 單例模式一般沒有接口,擴展性差
- 單例對象如果持有 Context 對象,容易引發(fā)內(nèi)存泄漏,最好使用 Application Context