微信公眾號搭建網(wǎng)站seo外推軟件
文章目錄
- 單例模式1??
- 特性💪
- 單例模式的類型與實現(xiàn):
- 類型
- 懶漢式實現(xiàn)(線程不安全)
- 懶漢式實現(xiàn)(線程安全)
- 雙重鎖校驗懶漢式(線程安全)
- 餓漢式實現(xiàn)(線程安全)
- 使用類的內(nèi)部類實現(xiàn)?
- 枚舉方式實現(xiàn)單例(推薦)👍
單例模式1??
單例模式是指在內(nèi)存中只會創(chuàng)建且僅創(chuàng)建一次對象的設(shè)計模式。讓你能夠保證一個類只有一個實例, 并提供一個訪問該實例的全局節(jié)點。
特性💪
- 唯一性:整個系統(tǒng)中,單例類只能有一個實例。
- 私有化構(gòu)造函數(shù):防止外部通過new關(guān)鍵字直接創(chuàng)建對象。
- 靜態(tài)方法提供全局訪問點:通常使用
getInstance()
方法來獲取該類的唯一實例。 - 延遲實例化(懶加載):有些實現(xiàn)會在第一次調(diào)用
getInstance()
時才創(chuàng)建實例,以節(jié)省資源。
單例模式的類型與實現(xiàn):
類型
- 懶漢式:在真正需要使用對象時才去創(chuàng)建該單例類對象
- 餓漢式:在類加載時已經(jīng)創(chuàng)建好該單例對象,等待被程序使用
懶漢式實現(xiàn)(線程不安全)
只有當調(diào)用getInstance()
方法時才會創(chuàng)建單例對象,這種方式實現(xiàn)了延遲加載,但是需要考慮多線程環(huán)境下的線程安全問題。
public class Singleton {private static Singleton instance;private Singleton() {}public static Singleton getInstance() {if (instance == null) {instance = new Singleton();}return instance;}
}
- 單例模式不允許外部直接創(chuàng)建,所以構(gòu)造函數(shù)添加私有屬性
private
- 這種方式滿足懶漢式,但是在并發(fā)場景下,多個線程使用單例對象可能導(dǎo)致實例并存,從而違反了單例要求
懶漢式實現(xiàn)(線程安全)
上述懶漢式實現(xiàn)是線程不安全的(例如同時兩個線程去獲取單例對象,如果此時單例對象還未創(chuàng)建,可能會導(dǎo)致同事創(chuàng)建兩個對象,從而違反單例),故我們要解決線程安全問題。
最容易想到的方法:使用鎖(synchronized
)給類加鎖來保證線程安全
public class Singleton {private static Singleton instance;private Singleton() {}public static synchronized Singleton getInstance() {if (instance == null) {instance = new Singleton();}return instance;}
}
雙重鎖校驗懶漢式(線程安全)
但是上述方法每次獲取對象的時候都要去先獲取鎖,并發(fā)性能不是很好
可以進行優(yōu)化:(如果沒有實例化則加鎖創(chuàng)建,如果實例化了則直接獲取,可以使得已經(jīng)實例化的單例對象在獲取單例對象時無需先獲取鎖,而是直接獲取對象)
使用Double Check(雙重校驗) + Lock(加鎖) 的寫法:
public class Singleton {private static volatile Singleton instance;private Singleton() {}public static Singleton getInstance() {if (instance == null) { // 第一次檢查,為了避免不必要的同步操作,提高性能。synchronized(Singleton.class) { if (instance == null) { // 第二次檢查,以確保即使在多線程環(huán)境下也只創(chuàng)建一個實例。instance = new Singleton();}}}return instance;}
}
同時我們也使用了volatile
關(guān)鍵字去確保instance
變量的更新對所有線程都是立即可見的,并且禁止指令重排序,保證多線程環(huán)境下的正確性。
- 防止指令重排序: 在多線程環(huán)境下,JVM為了優(yōu)化性能可能會對指令進行重排序。對于單例對象的創(chuàng)建而言,構(gòu)造函數(shù)內(nèi)部的操作可能被重排序到對象引用賦值之后。例如,如果一個線程正在執(zhí)行實例化操作,它可能會先將對象引用設(shè)置為非空(即指向一塊內(nèi)存),然后再完成對象的初始化。這種情況下,另一個線程可能看到的是一個部分初始化的對象(因為對象的引用不是
null
了),這會導(dǎo)致不可預(yù)測的行為或錯誤。volatile
關(guān)鍵字可以禁止這種指令重排序,保證對象完全初始化之后才會被其他線程看到。 - 可見性保證:
volatile
關(guān)鍵字確保了一個線程對共享變量(在這個場景下是單例對象的引用)的修改對于其他線程是立即可見的。也就是說,當一個線程成功創(chuàng)建了單例對象后,所有其他線程都能看到這個對象已經(jīng)被正確地初始化了,而不會讀取到舊的或者默認的值(如null
)。這避免了多個線程同時創(chuàng)建多個實例的情況。
餓漢式實現(xiàn)(線程安全)
在類加載的時候就創(chuàng)建好單例對象,這種方式簡單但不夠靈活,因為它不能做到延遲加載。
public class Singleton{private static final Singleton singleton = new Singleton();private Singleton(){}public static Singleton getInstance() {return singleton;}
}
在類加載的時候,private static final Singleton singleton = new Singleton();
這行代碼已經(jīng)實例化好了一個單例對象在內(nèi)存中。
使用類的內(nèi)部類實現(xiàn)?
利用了Java語言的類加載機制,只有當調(diào)用getInstance()
方法時,內(nèi)部類才會被加載,從而實現(xiàn)了懶加載和線程安全,同時不會因為加鎖的方式耗費性能。
public class Singleton {private Singleton() {}private static class SingletonHolder {private static final Singleton INSTANCE = new Singleton();}public static Singleton getInstance() {return SingletonHolder.INSTANCE;}
}
- 這主要是因為JVM虛擬機可以保證多線程并發(fā)訪問的正確性,也就是一個類的構(gòu)造方法在多線程環(huán)境下可以被正確的加載。
- 此種方式也是非常推薦使用的一種單例模式
枚舉方式實現(xiàn)單例(推薦)👍
在Java中,使用枚舉(Enum)來實現(xiàn)單例模式是一種非常簡潔且高效的方法。枚舉類型的單例不僅能夠防止反射攻擊和序列化導(dǎo)致的重復(fù)實例化問題,而且代碼量極少,易于理解和維護。這是因為Java的枚舉機制保證了每個枚舉常量的唯一性,并且在類加載時自動初始化。
public enum Singleton {INSTANCE;private final String property;// 初始化屬性值Singleton() {this.property = "Some Value";}public String getProperty() {return property;}// 其他業(yè)務(wù)方法public void doSomething() {// 方法邏輯...}
}public class Client {public static void main(String[] args) {Singleton singleton = Singleton.INSTANCE;singleton.doSomething();System.out.println(singleton.getProperty());}
}
枚舉單例的優(yōu)點:
- 天然線程安全:由于枚舉常量在類加載時就被初始化,所以不需要額外的同步代碼來保證線程安全。
- 防止反序列化創(chuàng)建新實例:枚舉類型具有內(nèi)在的序列化機制,如果嘗試反序列化一個枚舉類型的對象,它總是返回現(xiàn)有的枚舉常量,而不會創(chuàng)建新的實例。
- 防止反射攻擊:即使通過反射調(diào)用私有構(gòu)造函數(shù),也無法創(chuàng)建新的枚舉實例。
- 簡潔:相比于其他單例模式的實現(xiàn)方式,枚舉單例的代碼更加簡潔明了。
- 延遲加載:雖然枚舉類型不是天生支持懶加載,但是可以通過將實際的工作委托給另一個靜態(tài)內(nèi)部類來實現(xiàn)這一點。