繁体   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