簡體   English   中英

使用不同的線程刪除元素遍歷ConcurrentSkipListSet

[英]Iterating over ConcurrentSkipListSet with different thread removing elements

我有一個ConcurrentSKipListSet ,並且正在使用for-each循環遍歷該集合中的值。 某個時刻的另一個線程將從該集合中刪除一個元素。

我認為我正在遇到一種情況,即一個線程刪除了一個我要迭代的元素(或者也許我剛剛開始對其進行迭代),因此從循環內進行調用失敗。

為了清楚起見,一些代碼:

for(Foo foo : fooSet) {
  //do stuff

  //At this point in time, another thread removes this element from the set

  //do some more stuff
  callService(foo.getId()); // Fails
}

閱讀文檔,如果有可能,我無法解決:

迭代器是弱一致性的,返回的元素在創建迭代器時或創建迭代后的某個時間點會反映集合的狀態。 它們不會引發ConcurrentModificationException ,並且可以與其他操作並發進行。

那么這有可能嗎,如果可以的話,有什么好的方法來處理呢?

謝謝

我認為我正在遇到一種情況,即一個線程刪除了一個我要迭代的元素(或者也許我剛剛開始對其進行迭代),因此從循環內進行調用失敗。

我不認為這是javadocs在說的:

迭代器是弱一致性的,返回的元素在創建迭代器時或創建迭代后的某個時間點會反映集合的狀態。 它們不會引發ConcurrentModificationException,並且可以與其他操作並發進行。

這就是說,您不必擔心有人在遍歷整個列表的ConcurrentSkipListSetConcurrentSkipListSet中刪除。 有一定將一個競爭條件如您是通過迭代移動。然而。 foo可能迭代器獲取立即被刪除,或者在迭代器之前被刪除卻沒有看到它。

callService(foo.getId()); //這不應該“失敗”

如果foo由迭代器返回,則除非假定foo仍在列表中並以某種方式進行檢查,否則您的服務調用不會“失敗”。 最壞的情況是,即使其他線程剛剛將它從列表中刪除,您也可能會對foo進行一些操作並使用該服務調用該服務。

使用不同線程寫入和讀取的隊列也遇到了這個問題。 一種方法是標記而不是刪除不再需要的元素。 瀏覽整個列表后,可以運行清除迭代器。 您只需要全局鎖即可從列表中刪除元素,其余時間則可以並行運行代碼。 原理上它是這樣的:

writer:
  while() {
    set.add(something);
    something.markForDelete();
  }

reader:
  while() {
    // process async
    iterator iter = set.getIterator();
    for(iter.hasNext()) {
      ... work, check isMarkedForDelete() ...
    }
    iter = set.getIterator();

    // delete, sync
    globalLock.Lock();
    for(iter.hasNext()) {
      if(something.isMarkedForDelete()) {
      set.remove(something);
    }
    globalLock.Unlock();
  }
}

暫無
暫無

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

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