單例模式
介紹
單例模式可以說是整個設計中最簡單的模式之一,而且這種方式即使在沒有看設計模式相關資料也會常用在編碼開發中,
因為在編程開發中經常會遇到這樣一種場景,那就是需要保證一個類只有一個實體哪怕多執行緒同時訪問,并需要提供一個全域訪問此實體的點,
綜上以及我們平常的開發中,可以總結一條經驗,單例模式主要解決的是,一個全域使用的類頻繁的創建和消費,從而提升提升整體的代碼的性能,
8種單例模式實作
靜態類使用
/**
* [靜態類使用]
* 以上這種方式在我們平常的業務開發中非常場常見,這樣靜態類的方式可以在第一次運行的時候直接初始化Map類,同時這里我們也不需要到延遲加載在使用,
* 在不需要維持任何狀態下,僅僅用于全域訪問,這個使用使用靜態類的方式更加方便,
* 但如果需要被繼承以及需要維持一些特定狀態的情況下,就適合使用單例模式,
*/
public class Singleton_00 {
public static Map<String,String> cache = new ConcurrentHashMap<String, String>();
}
懶漢模式(執行緒不安全)
/**
* [懶漢模式(執行緒不安全]
* 單例模式有一個特點就是不允許外部直接創建,也就是new Singleton_01(),因此這里在默認的建構式上添加了私有屬性 private,
* 目前此種方式的單例確實滿足了懶加載,但是如果有多個訪問者同時去獲取物件實體你可以想象成一堆人在搶廁所,就會造成多個同樣的實體并存,從而沒有達到單例的要求,
*/
public class Singleton_01 {
private static Singleton_01 instance;
private Singleton_01() {
}
public static Singleton_01 getInstance(){
if (null != instance) return instance;
instance = new Singleton_01();
return instance;
}
}
懶漢模式(執行緒安全)
/**
* [懶漢模式(執行緒安全)]
* 此種模式雖然是安全的,但由于把鎖加到方法上后,所有的訪問都因需要鎖占用導致資源的浪費,如果不是特殊情況下,不建議此種方式實作單例模式,
*/
public class Singleton_02 {
private static Singleton_02 instance;
private Singleton_02() {
}
public static synchronized Singleton_02 getInstance(){
if (null != instance) return instance;
instance = new Singleton_02();
return instance;
}
}
餓漢模式(執行緒安全)
/**
* [餓漢模式(執行緒安全)]
* 此種方式與我們開頭的第一個實體化Map基本一致,在程式啟動的時候直接運行加載,后續有外部需要使用的時候獲取即可,
* 但此種方式并不是懶加載,也就是說無論你程式中是否用到這樣的類都會在程式啟動之初進行創建,
* 那么這種方式導致的問題就像你下載個游戲軟體,可能你游戲地圖還沒有打開呢,但是程式已經將這些地圖全部實體化,到你手機上最明顯體驗就一開游戲記憶體滿了,手機卡了,需要換了,
*/
public class Singleton_03 {
private static Singleton_03 instance = new Singleton_03();
private Singleton_03() {
}
public static Singleton_03 getInstance() {
return instance;
}
}
使用類的內部類(執行緒安全)
/**
* [使用類的內部類(執行緒安全)]
* 使用類的靜態內部類實作的單例模式,既保證了執行緒安全有保證了懶加載,同時不會因為加鎖的方式耗費性能,
* 這主要是因為JVM虛擬機可以保證多執行緒并發訪問的正確性,也就是一個類的構造方法在多執行緒環境下可以被正確的加載,
* 此種方式也是非常推薦使用的一種單例模式
*/
public class Singleton_04 {
private static class SingletonHolder {
private static Singleton_04 instance = new Singleton_04();
}
private Singleton_04() {
}
public static Singleton_04 getInstance() {
return SingletonHolder.instance;
}
}
雙重鎖校驗(執行緒安全)
/**
* [雙重鎖校驗(執行緒安全)]
* 雙重鎖的方式是方法級鎖的優化,減少了部分獲取實體的耗時,
* 同時這種方式也滿足了懶加載,
*/
public class Singleton_05 {
private static volatile Singleton_05 instance;
private Singleton_05() {
}
public static Singleton_05 getInstance(){
if(null != instance) return instance;
synchronized (Singleton_05.class){
if (null == instance){
instance = new Singleton_05();
}
}
return instance;
}
}
CAS「AtomicReference」(執行緒安全)
/**
* [CAS「AtomicReference」(執行緒安全)]
* java并發庫提供了很多原子類來支持并發訪問的資料安全性;AtomicInteger、AtomicBoolean、AtomicLong、AtomicReference,
* AtomicReference 可以封裝參考一個V實體,支持并發訪問如上的單例方式就是使用了這樣的一個特點,
* 使用CAS的好處就是不需要使用傳統的加鎖方式保證執行緒安全,而是依賴于CAS的忙等演算法,依賴于底層硬體的實作,來保證執行緒安全,相對于其他鎖的實作沒有執行緒的切換和阻塞也就沒有了額外的開銷,并且可以支持較大的并發性,
* 當然CAS也有一個缺點就是忙等,如果一直沒有獲取到將會處于死回圈中,
*/
public class Singleton_06 {
private static final AtomicReference<Singleton_06> INSTANCE = new AtomicReference<Singleton_06>();
private static Singleton_06 instance;
private Singleton_06() {
}
public static final Singleton_06 getInstance() {
for (; ; ) {
Singleton_06 instance = INSTANCE.get();
if (null != instance) return instance;
INSTANCE.compareAndSet(null, new Singleton_06());
return INSTANCE.get();
}
}
public static void main(String[] args) {
System.out.println(Singleton_06.getInstance()); // org.itstack.demo.design.Singleton_06@2b193f2d
System.out.println(Singleton_06.getInstance()); // org.itstack.demo.design.Singleton_06@2b193f2d
}
}
列舉單例(執行緒安全)
/**
* [列舉單例(執行緒安全)]
* Effective Java 作者推薦使用列舉的方式解決單例模式,此種方式可能是平時最少用到的,
* 這種方式解決了最主要的;執行緒安全、自由串行化、單一實體,
*/
public enum Singleton_07 {
INSTANCE;
public void test(){
System.out.println("hi~");
}
public static void main(String[] args) {
Singleton_07.INSTANCE.test();
}
}
小結
- 雖然只是一個很平常的單例模式,但在各種的實作上真的可以看到java的基本功的體現,這里包括了;懶漢、餓漢、執行緒是否安全、靜態類、內部類、加鎖、串行化等等,
- 在平時的開發中如果可以
確保此類是全域可用不需要做懶加載,那么直接創建并給外部呼叫即可,但如果是很多的類,有些需要在用戶觸發一定的條件后(游戲關卡)才顯示,那么一定要用懶加載,執行緒的安全上可以按需選擇,
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/325836.html
標籤:其他
下一篇:如何用電腦自帶的軟體錄屏
