設(shè)計模式代表了最佳的實踐
引言
- 創(chuàng)建型模式。
- 主要特點:簡單憔辫,樣式多趣些。
- 主要解決:一個全局使用的類頻繁地創(chuàng)建與銷毀。
- 關(guān)鍵代碼:構(gòu)造函數(shù)是私有的贰您。
說明
- 單例只能有一個實例坏平。
- 單例類必須自己創(chuàng)建自己的唯一實例。
- 單例類必須給所有其他對象提供這一實例锦亦。
優(yōu)缺點
- 優(yōu)點:內(nèi)存里只有一個實例舶替,減少了內(nèi)存的開銷(頻繁創(chuàng)建)。
- 缺點:沒有接口杠园,不能繼承顾瞪,與單一職責(zé)原則沖突。
實現(xiàn)方式
餓漢
public class Singleton {
private static final Singleton instance = new Singleton();
private Singleton() {
}
public static Singleton getInstance() {
return instance;
}
}
惡漢模式:沒有加鎖抛蚁,執(zhí)行效率高陈醒。但是類加載時就初始化,浪費內(nèi)存瞧甩,容易產(chǎn)生垃圾對象钉跷。
懶漢
public class Singleton {
private static Singleton instance;
private Singleton() {
}
public static synchronized Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
懶漢模式:第一次調(diào)用才初始化,解決了惡漢模式的內(nèi)存問題肚逸。但是每次獲取實例都需要同步爷辙,加鎖影響效率彬坏。
雙重檢查
public class Singleton {
private volatile static Singleton singleton;
private Singleton() {
}
public static Singleton getSingleton() {
if (singleton == null) {
synchronized (Singleton.class) {
if (singleton == null) {
singleton = new Singleton();
}
}
}
return singleton;
}
}
雙重檢查模式
- 第一次判空:在已經(jīng)實例化的情況下(99.99%的情況),省去了同步操作膝晾。
- synchronized:在首次實例化時栓始,保證線程同步。
- 第二次判空:在首次實例化遇到多線程問題時(鎖生效的場景)血当,完成實例化后的線程執(zhí)行不再次進(jìn)行實例化處理幻赚。
- volatile:保證并發(fā)場景的有序性。
為什么要保證有序性歹颓?
?對象創(chuàng)建的執(zhí)行步驟如下:
-
正常情況
- 1.分配空間
- 2.初始化
- 3.引用賦值
-
重排情況(JIT優(yōu)化)
- 1.分配空間
- 2.引用賦值
- 3.初始化
?在單線程模型的場景下坯屿,指令重排不會影響執(zhí)行結(jié)果。JIT指令重排的優(yōu)化巍扛,并不會考慮并發(fā)場景。
?從上面的重排時序上看乏德,就發(fā)現(xiàn)了為什么要使用volatile來保證有序性了撤奸。因為引用賦值在前,初始化在后喊括,會導(dǎo)致singleton引用已經(jīng)不為空了胧瓜,但是還沒有初始化,調(diào)用線程會拿到一個沒有初始化的引用進(jìn)行方法調(diào)用郑什,會異常奔潰府喳。
ps:如果想查看對象的創(chuàng)建執(zhí)行步驟,可以使用以下命令:
- 生成字節(jié)碼文件:javac XX.java蘑拯;
- 對生成的字節(jié)碼文件反匯編:javap -c -v XX.class钝满;
- 通過匯編指令以及常量池序號,對應(yīng)進(jìn)行查找即可申窘。
靜態(tài)內(nèi)部類
public class Singleton {
private static class SingletonHolder {
private static final Singleton INSTANCE = new Singleton();
}
private Singleton() {
}
public static final Singleton getInstance() {
return SingletonHolder.INSTANCE;
}
}
靜態(tài)內(nèi)部類模式:實現(xiàn)更簡單弯蚜。
枚舉
public enum Singleton {
INSTANCE;
public void todo() {
}
}
枚舉模式:實現(xiàn)單例模式的最佳方法。更簡潔剃法,自動支持序列化機(jī)制碎捺,防止反序列化。缺點就是可讀性差(這玩意兒咋看都不像單例)贷洲。
實現(xiàn)方式總結(jié)
?