如何正確實現多執行緒環境中的單例模式
阿新 • • 發佈:2018-11-06
要實現單例模式,馬上可以想到的有三種方法:
- 餓漢式
- 懶漢式
- 有且只有一個例項的列舉
如何正確地在多執行緒環境下實現單例模式呢?
對於 餓漢式 和 單例項列舉 來說,它們都是利用jvm類載入機制來實現單例模式。使用這兩種方法,無論是否是在多執行緒環境中,都可以保證正確實現單例。但是 懶漢式 會有一些問題。
很多地方,使用懶漢式實現是這樣做的:
public class Single { private static Single single; private Single() {} private static Single getInstance() { if (single == null) { synchronized (Single.class) { if (single == null) { single = new Single(); SleepTools.second(10); } } } return single; } }
問題在於:當A執行緒首先訪問getInstance()方法時,執行到了休眠方法,並進入休眠狀態(這裡只是為了說明,如果Single這個類有很多成員變數,或者構造出一個例項要用很長時間,比如:要查資料庫什麼的);這時如果B執行緒正好進入,那麼B執行緒看到的 single 是不為 null 的,那麼B可以直接獲得Single的例項物件,問題在於,當B執行緒在後續使用這個單例的成員變數時,就有可能出現 空指標異常。
正確得使用 懶漢式 來實現單例
public class Single { private static Single single; private Single() { } private static Single getSingle(){ return Inner.getSingle(); } private static class Inner{ private static Single single = new Single(); static Single getSingle(){ return single; } } }
在要實現單例的類中引入一個內部類,專門用來初始化外部類。這樣既可以保證單例,又要以保證在需要時才例項化。