一、什麼是單例
單例提供了一種創建對象的方式,確保只有單個對象被創建,設計目的是保證整個應用中有且只有一個實例
優點
- 節約資源
- 不用頻繁的創建對象,一定程度減少內存泄漏和內存溢出的風險
二、設計思想
要保證整個應用中只有一個實例,要保證
1、不允許其他程序 new 對象
因爲每次new都會產生一個新的對象,這樣保證不了對象的唯一性。
2、在該類中創建對象
有了1的前提,那new對象的事只能交給本類來做,在類的內部,new一個對象
3、對外提供獲取對象的方法
對象在本類中創建,其他類要調用的話,需要在本類中提供一個方法可讓其他類進行調用對象
二、實現步驟
基於上面的設計思想,具體實現步驟如下:
- 構造函數私有化
- 在本類中 new 一個對象
- 提供一個靜態方法獲取實例(注意多線程問題)
三、實現方式
1、餓漢式(線程安全)
public class Singleton1 {
private static final Singleton1 INSTANCE = new Singleton1();
// 提供靜態方法獲取實例
public static Singleton1 getInstance() {
return INSTANCE;
}
}
- 優點:簡單粗暴、類加載的時候就初始化完成,線程安全
- 缺點:不可延遲加載,類加載時就初始化,可能會造成不必要的內存浪費
2、懶漢式(線程不安全)
public class Singleton2 {
private static Singleton2 instance;
// 構造函數私有化
private Singleton2() {
}
// 提供靜態方法獲取實例
public static Singleton2 getInstance() {
if (instance == null) {
instance = new Singleton2();
}
return instance;
}
}
- 優點:延遲初始化,減少不必要內存消耗
- 缺點:線程不安全
3、懶漢式(線程安全,同步方法)
public class Singleton3 {
private Singleton3() {
}
private static Singleton3 instance;
public static synchronized Singleton3 getInstance() {
if (instance == null) {
instance = new Singleton3();
}
return instance;
}
}
- 優點:延遲初始化,減少不必要內存消耗,線程安全
- 缺點:效率偏低,每次獲取實例都進行同步鎖,事實上只需要在第一次new對象的時候同步鎖就行了,後續想獲取實例可以直接返回。
4、懶漢式(線程安全,同步代碼塊)(DCL 雙重檢查)
public class Singleton4 {
// volatile : 防止指令重排序
private volatile static Singleton4 instance;
private Singleton4() {
}
public static Singleton4 getInstance() {
if (instance == null) {
synchronized (Singleton4.class) {
if (instance == null) {
instance = new Singleton4();
}
}
}
return instance;
}
}
- 優點:延遲初始化,減少不必要內存消耗,線程安全,裝逼大佬推薦使用這個
5、靜態內部類
public class Singleton5 {
private static final class SingletonHolder {
private static final Singleton5 INSTANCE = new Singleton5();
}
public static Singleton5 getInstance() {
return SingletonHolder.INSTANCE;
}
}
推薦使用
6、枚舉
public enum Singleton6 {
INSTANCE;
String getMethod() {
return "枚舉單例";
}
// 方法調用: Singleton6.INSTANCE.getMethod()
}
《Effective Java》中推薦的模式 ,但是閱讀性不高,Android中使用枚舉會有一定的內存開銷
四、總結
線程安全 | 併發性能好 | 延遲初始化 | 序列化/反序列化安全 | 能抵禦反射攻擊 | ||
---|---|---|---|---|---|---|
餓漢式 | Y | Y | ||||
懶漢式 | 不加鎖 | Y | Y | |||
懶漢式(加鎖的) | Y | Y | ||||
DCL(雙重檢查) | Y | Y | Y | |||
靜態內部類 | Y | Y | Y | |||
枚舉 | Y | Y | Y | Y |
4、5、6 都是推薦使用的,但是6的話,在Android中用的人不多,4的話從代碼上反應出來了怎麼解決懶加載和線程安全問題。