簡體   English   中英

java-iterator.remove()如果在迭代時修改了set

[英]java - iterator.remove() if set is modified while iteration

我有一個由多個線程連續擴展的Set:

Set<String> concurrentSet = new CopyOnWriteArraySet<>();

有時我會處理集合中的元素,由於不再需要已處理的元素,因此可以使用iterator.remove()刪除它們:

Iterator<String> i = concurrentSet .iterator();
while (i.hasNext()) {
    String str = i.next();
    //processing...
    i.remove();
}

這是線程安全的嗎? 如果線程在迭代時添加元素怎么辦?

注意: 文檔指出“如果在迭代進行過程中以其他方式(而不是通過調用此方法)修改基礎集合,則未指定迭代器的行為。” => CopyOnWriteArraySet也是如此嗎?

我認為這適用於集合不是線程安全的情況。 本來應該添加ConcurrentHashset來處理這種情況。

這取決於您使用的線程安全實現。 例如:

  • CopyOnWriteArraySet javadoc指出:“ 迭代器不支持可變的remove操作。 ” =>如果調用it.remove()則會出現異常。
  • ConcurrenSkipListSet javadoc狀態:“ 插入,刪除和訪問操作可以安全地由多個線程同時執行。迭代器是弱一致性的,在創建迭代器時或創建迭代器后的某個時刻返回反映集合狀態的元素。 ” =>您可以放心假設調用it.remove()是線程安全的(因為它不會引發ConcurrentModificationException)。

但是請注意:

if (it.hasNext()) {
    it.next();
    it.remove();
}

不是原子的,因此如果同時修改集合,該操作的結果可能是意外的。

CopyOnWriteArraySet是線程安全的,但是Iterators不支持可變刪除操作,您可以使用CopyOnWriteArraySet#remove刪除ovject,但由於所有此可變操作(添加,設置,刪除等)都非常昂貴,因此對該數據結構的操作非常昂貴操作完全復制整個基礎數組。

在documentaton上找到更多信息

從Java 7 JavaDoc( http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/CopyOnWriteArraySet.html ):

[CopyOnWriteArraySet]迭代器不支持可變刪除操作。

如果線程安全比性能更重要,我建議您沿Collections.synchronizedSet的方式使用。 使用起來比較困難,您必須使用迭代器將代碼顯式地包裝在synceded(set){}塊中,但是可以保證所有操作都是線程安全的。

如果需要同時進行並發和線程安全,則可以通過ReentrantReadWriteLock將普通的HashSet與自己的顯式鎖定一起使用。 如果正確實現,這將允許讀取並發和寫入線程安全。 我不知道Java API中有一個與此相關的標准類,但是那里可能有一個(或者實際上在其他地方,例如Apache Commons Collections)。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM