轉:https://www.jianshu.com/p/9c32aea34b6d
單例模式是運用最廣泛的設計模式之一,在應用這個模式時,單例模式的類必須保證只有一個實例存在。多用于整個程序只需要有一個實例,通常很消耗資源的類,比如線程池,緩存,網絡請求,IO操作,訪問數據庫等。由于類比較耗資源,所以沒必要讓它構造多個實例,這種就是單例模式比較好的使用場景。確保一個類只有一個實例,并且自行實例化。向整個系統提供這個唯一的實例。
幾個關鍵點:
1.構造函數用private,讓外部無法訪問,就沒辦法去重寫實例化
2.使用最關鍵的關鍵詞static,針對他的特性,內存中只有一份數據。
如:
public class SingletionStarving {private static final SingletionStarving mInstance = new SingletionStarving();private SingletionStarving() {}public static SingletionStarving getInstance() {return mInstance;}
}
實用的寫法:
public class SingletionDLC {private volatile static SingletionDLC mInstance;private SingletionDLC() {}public static SingletionDLC getmInstance() {if (mInstance == null) {synchronized (SingletionDLC.class) {if (mInstance == null) {mInstance = new SingletionDLC();}}}return mInstance;}
}
1、構造函數用private修飾,外部無法訪問
2、使用的時候即調用getInstance的時候才初始化
3、static關鍵字修飾,靜態變量,存儲在內存中,只有一份數據
4、synchronized線程安全,多線程情況下單例的唯一性
5、兩次判斷空,避免多次同步(synchronized)
synchronized的作用是保證在同一時刻, 被修飾的代碼塊或方法只會有一個線程執行,以達到保證并發安全的效果。
volatile 說白了就是被修飾的變量會被不同的線程訪問和修改,也是一個輕量級的同步機制
可見性:當某一個線程對共享變量的修改,其他線程可以立刻看到修改之后的值
防止編譯器優化:編譯器在優化代碼時會嘗試將變量的訪問操作優化為更高效的方式,例如將變量的值緩存在寄存器中。然而,對于某些特殊的變量,如多線程環境下的共享變量、中斷處理中的標志位、硬件寄存器等,這種優化可能會導致意外的行為。使用 volatile 關鍵字可以告訴編譯器不要對該變量進行優化,確保每次訪問都從內存中讀取或寫入。
處理多線程共享變量:在多線程編程中,當一個變量被多個線程共享并且可能被一個線程修改時,需要使用 volatile 關鍵字來確保線程之間的可見性。這樣可以防止編譯器對共享變量的優化,確保每個線程都能正確地讀取到最新的值。
處理中斷和硬件寄存器:在中斷處理程序中,某些變量可能由硬件直接修改,而不是通過常規的變量賦值操作。在這種情況下,使用 volatile 關鍵字可以確保編譯器不會對這些變量的訪問進行優化,以避免出現不一致的行為。
內部類的方式,也推薦使用
public class SingletionInternalClass {private SingletionInternalClass() {}public static SingletionInternalClass getInstance() {return SingletionInternalClassHolder.instance;}private static class SingletionInternalClassHolder {private static final SingletionInternalClass instance = new SingletionInternalClass();}
}