1. 程式人生 > >如何正確實現多執行緒環境中的單例模式

如何正確實現多執行緒環境中的單例模式

要實現單例模式,馬上可以想到的有三種方法:

  1. 餓漢式
  2. 懶漢式
  3. 有且只有一個例項的列舉

如何正確地在多執行緒環境下實現單例模式呢?

對於 餓漢式單例項列舉 來說,它們都是利用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;
        }
    }
}

在要實現單例的類中引入一個內部類,專門用來初始化外部類。這樣既可以保證單例,又要以保證在需要時才例項化。