简体   繁体   English

使用不同的线程删除元素遍历ConcurrentSkipListSet

[英]Iterating over ConcurrentSkipListSet with different thread removing elements

I have a ConcurrentSKipListSet , and I'm iterating over values in this set with a for-each loop. 我有一个ConcurrentSKipListSet ,并且正在使用for-each循环遍历该集合中的值。 Another thread at some point is going to remove an element from this set. 某个时刻的另一个线程将从该集合中删除一个元素。

I think I'm running into a situation where one thread removes an element that I'm yet to iterate over (or maybe I've just started to iterate over it) and so a call being made from within the loop fails. 我认为我正在遇到一种情况,即一个线程删除了一个我要迭代的元素(或者也许我刚刚开始对其进行迭代),因此从循环内进行调用失败。

Some code for clarity: 为了清楚起见,一些代码:

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
}

Reading the docs I can't work out if this is possible or not: 阅读文档,如果有可能,我无法解决:

Iterators are weakly consistent, returning elements reflecting the state of the set at some point at or since the creation of the iterator. 迭代器是弱一致性的,返回的元素在创建迭代器时或创建迭代后的某个时间点会反映集合的状态。 They do not throw ConcurrentModificationException , and may proceed concurrently with other operations. 它们不会引发ConcurrentModificationException ,并且可以与其他操作并发进行。

So is this possible, and if so, what's a good way of handling this? 那么这有可能吗,如果可以的话,有什么好的方法来处理呢?

Thanks 谢谢

Will

I think I'm running into a situation where one thread removes an element that I'm yet to iterate over (or maybe I've just started to iterate over it) and so a call being made from within the loop fails. 我认为我正在遇到一种情况,即一个线程删除了一个我要迭代的元素(或者也许我刚刚开始对其进行迭代),因此从循环内进行调用失败。

I don't think that's what the javadocs are saying: 我不认为这是javadocs在说的:

Iterators are weakly consistent, returning elements reflecting the state of the set at some point at or since the creation of the iterator. 迭代器是弱一致性的,返回的元素在创建迭代器时或创建迭代后的某个时间点会反映集合的状态。 They do not throw ConcurrentModificationException, and may proceed concurrently with other operations. 它们不会引发ConcurrentModificationException,并且可以与其他操作并发进行。

This is saying that you don't have to worry about someone removing from the ConcurrentSkipListSet at the same time that you are iterating across the list. 这就是说,您不必担心有人在遍历整个列表的ConcurrentSkipListSetConcurrentSkipListSet中删除。 There certainly is going to be a race condition as you are moving across the iterator however. 有一定将一个竞争条件如您是通过迭代移动。然而。 Either foo gets removed right after your iterator gets it or it was removed right before and the iterator doesn't see it. foo可能迭代器获取立即被删除,或者在迭代器之前被删除却没有看到它。

callService(foo.getId()); callService(foo.getId()); // this shouldn't "fail" //这不应该“失败”

If foo gets returned by the iterator, your service call won't "fail" unless it is assuming that the foo is still in the list and somehow checking it. 如果foo由迭代器返回,则除非假定foo仍在列表中并以某种方式进行检查,否则您的服务调用不会“失败”。 The worst case is that you might do some operations on foo and call the service with it even though it was just removed from the list by the other thread. 最坏的情况是,即使其他线程刚刚将它从列表中删除,您也可能会对foo进行一些操作并使用该服务调用该服务。

I've hit this problem as well with queues that are written to and read by different threads. 使用不同线程写入和读取的队列也遇到了这个问题。 One approach is to mark instead of remove elements that are no longer needed. 一种方法是标记而不是删除不再需要的元素。 You can run a cleanup iterator after you go through the whole list. 浏览整个列表后,可以运行清除迭代器。 You need a global lock just for removing elements from the list, and the rest of the time your code can run in parallel. 您只需要全局锁即可从列表中删除元素,其余时间则可以并行运行代码。 Schematically it works like this: 原理上它是这样的:

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