singleton模式四種執行緒安全的實現
1.描述:
Singleton(單例)是設計模式的一種,為了保證一個類僅有一個例項,並提供一個訪問它的全域性訪問點。
2.主要特點:
1)單例類確保自己只有一個例項(建構函式私有:不被外部例項化,也不被繼承)。
2)單例類必須自己建立自己的例項。
3)單例類必須為其他物件提供唯一的例項。
3.單例模式的應用:
資源管理器,回收站,印表機資源,執行緒池,快取,配置資訊類,管理類,控制類,門面類,代理類通常被設計為單例類
如果程式有多個類載入器又同時使用單例模式就有可能多個單例並存就要找相應解決方法了
4.實現方法:
如果應用程式總是建立並使用單例例項或在建立和執行時開銷不大。
1).Eager initialization 餓漢式單例類(依賴jvm在載入類時建立唯一單例例項)
- publicclass EagerSingleton {
- // jvm保證在任何執行緒訪問uniqueInstance靜態變數之前一定先建立了此例項
- privatestatic EagerSingleton uniqueInstance = new EagerSingleton();
- // 私有的預設構造子,保證外界無法直接例項化
- private EagerSingleton() {
-
}
- // 提供全域性訪問點獲取唯一的例項
- publicstatic EagerSingleton getInstance() {
- return uniqueInstance;
- }
- }
2)Lazy initialization 懶漢式單例類
- publicclass LazySingleton {
-
privatestatic
- private LazySingleton() {
- }
- publicstaticsynchronized LazySingleton getInstance() {
- if (uniqueInstance == null)
- uniqueInstance = new LazySingleton();
- return uniqueInstance;
- }
- }
3)"雙檢鎖"(Double-Checked Lock)儘量將"加鎖"推遲,只在需要時"加鎖"(僅適用於Java 5.0 以上版本,volatile保證原子操作)
happens-before:"什麼什麼一定在什麼什麼之前執行",也就是保證順序性.
現在的CPU有亂序執行的能力(也就是指令會亂序或並行執行,可以不按我們寫程式碼的順序執行記憶體的存取過程),並且多個CPU之間的快取也不保證實時同步,只有上面的happens-before所規定的情況下才保證順序性.
JVM能夠根據CPU的特性(CPU的多級快取系統、多核處理器等)適當的重新排序機器指令,使機器指令更符合CPU的執行特點,最大限度的發揮機器的效能.
如果沒有volatile修飾符則可能出現一個執行緒t1的B操作和另一執行緒t2的C操作之間對instance的讀寫沒有happens-before,可能會造成的現象是t1的B操作還沒有完全構造成功,但t2的C已經看到instance為非空,這樣t2就直接返回了未完全構造的instance的引用,t2想對instance進行操作就會出問題.
volatile 的功能:
1. 避免編譯器將變數快取在暫存器裡
2. 避免編譯器調整程式碼執行的順序
優化器在用到這個變數時必須每次都小心地重新讀取這個變數的值,而不是使用儲存在暫存器裡的備份。
- publicclass DoubleCheckedLockingSingleton {
- // java中使用雙重檢查鎖定機制,由於Java編譯器和JIT的優化的原因系統無法保證我們期望的執行次序。
- // 在java5.0修改了記憶體模型,使用volatile宣告的變數可以強制遮蔽編譯器和JIT的優化工作
- privatevolatilestatic DoubleCheckedLockingSingleton uniqueInstance;
- private DoubleCheckedLockingSingleton() {
- }
- publicstatic DoubleCheckedLockingSingleton getInstance() {
- if (uniqueInstance == null) {
- synchronized (DoubleCheckedLockingSingleton.class) {
- if (uniqueInstance == null) {
- uniqueInstance = new DoubleCheckedLockingSingleton();
- }
- }
- }
- return uniqueInstance;
- }
- }
- publicclass LazyInitHolderSingleton {
- private LazyInitHolderSingleton() {
- }
- privatestaticclass SingletonHolder {
- privatestaticfinal LazyInitHolderSingleton INSTANCE = new LazyInitHolderSingleton();
- }
- publicstatic LazyInitHolderSingleton getInstance() {
- return SingletonHolder.INSTANCE;
- }
- }