2011-05-12 69 views
3

如何確保initialize()方法只被調用一次?下面是我想重構使用AtomicBoolean的線程不安全版本。 所有我想要的是初始化()只調用一次如何使用AtomicBoolean實現此目的?

if (!initialized) 
{ 
    initialize(); 
    initialized = true; 
} 
+0

當然,'初始化()'完成之前的代碼可能會退出。 – 2011-05-12 21:33:22

+1

關鍵是使用'AtomicBoolean',它允許您在沒有代價高昂的同步的情況下執行原子更新(它使用CPU CAS操作和volatile變量)。 – 2011-05-12 21:34:58

回答

4
private final AtomicBoolean initialized = new AtomicBoolean(false); 


//in some method: 

if(!initialized.getAndSet(true)) 
{ 
    initialize(); 
} 
+1

我不認爲這是安全的。它_will_保證initialize()只被調用一次,但是第二個線程在getAndSet()之前不會被延遲,直到第一個線程完成初始化。 – 2011-05-12 22:33:31

+3

...因此,它會相信對象將被初始化,但事實並非如此。此解決方案無效,不應使用。 – JVerstry 2011-05-14 21:13:21

3

一個原子布爾不會被足夠多的適合你,因爲輸入代碼塊中的第二個線程將throught下降,即使有沒有初始化還沒有完成。試試這個,這將阻止第二,平行只有當第尚未完成,而且會非常快,當初始化完成:

volatile boolean initialized = false; 

private final Object LOCK = new Object(); 

public void ensureInitialized() { 
    if(!initialized) { 
     synchronized(LOCK) { 
      if(!initialized) { 
       initialize(); 
       initialized = true; 
      } 
     }  
    } 
} 

這也被稱爲雙重檢查鎖定ideom,這它的做法是正確的。

+1

可以依靠'this'而不是創建一個虛擬鎖對象()。 – JVerstry 2011-05-14 21:03:42

+0

取決於上下文,但是:是的。 – Daniel 2011-05-15 11:47:09

+0

請記住,鎖定'this'在某些圈子中被認爲是反模式。 http://stackoverflow.com/questions/442564/avoid-synchronizedthis-in-java?lq=1 – 2016-02-04 17:01:00

0

其實,你並不需要一個原子布爾用下面的代碼:

public class YourClass() { 

    volatile boolean initialized = false; 

    public void ensureInitialized() { 

     if (initialized) return; 

     synchronized(this) { 
      if (!initialized) { 
       initialize(); 
       initialized = true; 
      } 
     } 

    } 

    // The code of this method could be moved 
    // into the synchronized statement above 
    public void initialize() { ... }; 

} 

由於初始化代碼只會被調用一次,沒有真正的好處是用一個的AtomicBoolean。

在'this'上同步可能需要更多時間,但創建AtomicBoolean也是如此。這兩個操作只發生一次。

總體而言,此解決方案使用較少的內存。

編輯:更新的解決方案

+1

-1,這可能會導致雙重初始化。我不知道在寫完之後我們只是試着發佈我的解決方案,然後你也做錯了。 – Daniel 2011-05-13 05:58:46

+0

是的,我忘了如果在同步。我已更新我的解決方案。 – JVerstry 2011-05-13 14:02:15

+1

仍然錯誤。如果在初始化之前設置初始化的變量,則第二個線程在初始化完成之前可能仍會通過。抱歉。 – Daniel 2011-05-14 20:32:36