2013-05-14 88 views
2

我遇到了一個單例類{lazy initialization}。代碼如下懶惰初始化具有volatile變量的Singleton類

// Singleton reference for this class 
    private static volatile FileProperties INSTANCE = null; 

    public static FileProperties getInstance() { 
      if (INSTANCE == null) { 
       synchronized (FileProperties.class) { 
        if (INSTANCE == null) { 
         INSTANCE = new FileProperties(); 
        } 
       } 
      } 
      return INSTANCE; 
     } 

我的問題是什麼是我們正在通過使實例作爲揮發性 既然我們已經照顧線程安全的通過同步獲取利益。 在這種情況下是否有揮發性的好處?

+1

請參閱http://jeremymanson.blogspot.co.uk/2008/05/double-checked-locking.html – 2013-05-14 11:51:59

+1

這種雙重檢查的鎖定有一個潛在的錯誤,因爲INSTANCE變量可能被賦予一個非空值*之前* FileProperties的構造函數已完全執行。當然,如果構造函數是空的,這並不重要。 – 2013-05-14 11:55:14

+1

@JakobJenkov也許值得澄清:** IF ** INSTANCE不易變。 – assylias 2013-05-14 11:56:34

回答

5

這是因爲沒有volatile的雙重檢查鎖定在Java中不是線程安全的。

,使線程安全的lazy-init來單最簡單的方法是創建類持有人如下:

public class SomeClass { 
    private static class SomeClassHolder { 
     public static final SomeClass INSTANCE = new SomeClass(); 
    } 

    public static SomeClass getInstance() { 
     return SomeClassHolder.INSTANCE; 
    } 

    private SomeClass() {} 

} 

的代碼部分,因爲JVM的行爲將加載SomeClassHolder和創建SomeClass的實例第一次使用getInstance()(而不是當SomeClass由類加載器加載時)。

根本不需要使用任何同步!因爲JVM正在爲你做。

+0

自從volatile引發「發生在......之前」(Java 1.5)以來,雙重檢查鎖定一直是線程安全的。此外,你錯過了一個私有的構造函數 – Bohemian 2013-05-14 11:59:48

+1

只要你還*使用'volatile',DCL *就是從Java 1.5開始的Java中的線程安全的。 (我不會自己使用它,但是它是線程安全的。) – 2013-05-14 12:00:01

+0

@ Bohemian:我相信''volatile'在Java中是1.0。由於內存模型在1.5版本中改變,所以正確實施的DCL是線程安全的。 – 2013-05-14 12:00:26