2012-09-19 113 views
4

基於this topic,我放下了一個有趣的Singleton模式,其實現基於AtomicIntegers。這個Singleton是一個線程安全的嗎?

的問題是:

  • 這是實現正確的,線程安全的,一般是有可能使用原子變量進行線程同步和管理?
  • 其他問題:如果這個實現是線程安全的,我真的需要一個volatile修飾符的實例變量嗎?
public class StrangeSingleton 
{ 

    private StrangeSingleton() {}; 

    private static volatile Object instance; 

    private static AtomicInteger initCounter = new AtomicInteger(); 
    private static AtomicInteger readyCounter = new AtomicInteger(); 

    static Object getInstance() 
    { 

     if (initCounter.incrementAndGet() == 1) 
     { 
      instance = new Object(); 

      readyCounter.incrementAndGet(); 

      return instance; 
     } 
     else if (readyCounter.get() == 1) 
     { 
      return instance; 
     } 
     else 
     { 
      //initialization not complete yet. 
      //write here some logic you want:    
      //sleep for 5s and try one more time, 
      //or throw Exception, or return null.. 

      return null; 
     } 
    } 
} 

更新:增加了私有的構造函數,但它不是重點。

+2

您錯過了私有構造函數! – Santosh

+0

當有人可以調用'new StrangeSingleton()'時,它怎麼可能是單例。創建一個不帶任何參數的私有構造函數。 – km1

+2

你可以使用'AtomicBoolean'而不是'AtomicInteger'。使用'compareAndSet()'。 – Gray

回答

8

此實現是否正確且線程安全,並且通常可以使用Atomic Variables進行線程同步和管理?

它是但它通常更復雜和CPU密集型,因爲你需要忙於等待快速響應變化。

附加問題:如果這個實現是線程安全的,我真的需要一個volatile修飾符用於實例變量嗎?

在這種情況下,您不會因爲AtomicInteger包含可確保正確發生行爲之前/之後發生行爲的易失性字段。


當然,你可以只使用一個枚舉類型,是線程安全和更簡單;)

enum Singleton { 
    INSTANCE; 
} 
+0

彼得,這與通常的雙重檢查鎖定機制(從性能角度來看)相比如何? – Santosh

+0

雙重檢查鎖定會比檢查兩個AtomicXxxxx更快。使用'enum'是最快的,因爲它不需要一個易失字段並且不需要檢查。 –

+1

@Santosh由於某些實現語義的原因,在1.4及更早版本的所有平臺上雙鎖也不一定安全。 ([Wikipedia article。](http://en.wikipedia.org/wiki/Double-checked_locking#Usage_in_Java))這在5+中不是問題。還有,+1 – Brian

2

這是實現正確的,線程安全的,一般是有可能使用原子線程同步和管理的變量?

是的,但對於readyCounter變量,你應該使用一個CountDownLatch,像這樣:

private static AtomicInteger initCounter = new AtomicInteger(); 
private static CountDownLatch readyCounter = new CountDownLatch(1); 

static Object getInstance() 
{ 

    if (initCounter.incrementAndGet() == 1) 
    { 
     try { 
      instance = new Object(); 
      return instance; 
     } finally { 
      readyCounter.countDown(); 
     } 
    } 
    else 
    { 
     readyCounter.await(); 
     return instance; 
    } 
} 

調用等待()也解決了初始化競爭條件。 (我還添加了try-finally塊以避免構造函數異常造成死鎖)。

其他問題:如果此實現是線程安全的,那麼是否真的需要一個volatile變量來指定實例變量?

不,如果您在訪問實例變量之前調用相關的AtomicIntegerCountDownLatch函數,則不行。尋找發生在之前documentation

+0

Latch的大odea,謝謝,Soulman! – KutaBeach

0

螺紋T1可懸浮於instance = new Object();,然後T2將擊中else{}塊自readyCounter尚未遞增。 Thtat是不太正確的,因爲初始化完成,什麼是落後的狀態簿記

0

我寧願做一個​​塊在getInstance()方法。這已經足夠了。你不需要這些奇怪的計數器,它也不像@David注意到的那麼安全。

相關問題