2014-02-18 46 views
3

我有多線程環境中沒有邏輯問題的情況,但是我擔心Java Set的迭代器是否會在某些特定情況下中斷。我不知道這是否會崩潰後一段時間或不:是爲每個迭代線程安全嗎?

class Bar{ 
    AtomicLong a = 0; 
    AtomicLong b = 0; 

    public void addA(int value){ 
     a.addAndGet(value); 
    } 
    public void addB(int value){ 
     b.addAndGet(value); 
    } 
} 

class Foo{ 
    Set<Bar> bars = new CopyOnWriteArraySet(); 

    public void addBarData(Bar bar){ 
     if (!bars.add(bar)){ 
      for (Bar b: bars){ 
       if (bar.equals(b)){ 
        b.addA(bar.a); 
        b.addB(bar.b); 
       } 
      } 
     } 
    } 
} 

的問題可能是,如果兩個線程都在附近時調用addBarData(barInstance),一個是IFS體內侵入,然後開始迭代for-each,但另一個在那一刻添加另一個元素到集合中。 for-loop(或迭代器)會因爲元素數量的變化而崩潰嗎?

+0

請參閱:http://stackoverflow.com/questions/4517653/thread-safe-iteration-over-a-collection – pedromss

回答

2

在你的問題中的代碼看起來是線程安全的,因爲:

  • Bar使用AtomicLong這是原子和線程安全的。
  • CopyOnWriteArraySet也是線程安全的(它會在每次寫入操作時複製整個數組)。

所以這一切是線程安全的,你不會得到ConcurrentModificationException,而這個代碼的結果是可以預測的,因爲你通過遍歷集合實際上是不可改變的。

+0

我的關注點是關於遍歷新元素的集合(其他線程可能會添加新元素) – Sasa

+0

現在,其他線程可以添加新元素,但只有在添加操作結束後開始迭代的線程纔可見。 如果您需要立即查看新元素,則不能使用'CopyOnWriteArraySet',但(例如'LinkedHashSet')。使用'LinkedHashSet'你還需要添加同步塊。 –

+0

這回答了我的問題,謝謝。 – Sasa

2

不,每個循環只是一個編譯器魔術,相當於Iterator用於收集和索引數組的迭代。它不會添加任何其他效果,如線程安全性。

+0

你的意思是它不會崩潰,或者它會?我正在使用CopyOnWriteArraySet,它會防止這種崩潰? – Sasa

+1

只有修改集合時纔會發生崩潰。您的示例中沒有任何內容似乎正在修改集合,因此它不會崩潰。如果某些內容正在修改集合,則需要限制使用鎖定或使用寫入時複製或類似集合。 – Charlie

+0

但是你無法修改你迭代的集合。 –