Java 使用不同的线程删除元素在ConcurrentSkipListSet上迭代

Java 使用不同的线程删除元素在ConcurrentSkipListSet上迭代,java,multithreading,set,java.util.concurrent,Java,Multithreading,Set,Java.util.concurrent,我有一个ConcurrentSKipListSet,我用为每个循环迭代这个集合中的值。 另一个线程在某个时刻将从这个集合中删除一个元素 我想我遇到了这样一种情况:一个线程删除了一个我还没有迭代的元素(或者我刚刚开始迭代),因此从循环中进行的调用失败 为了清晰起见,有一些代码: for(Foo foo : fooSet) { //do stuff //At this point in time, another thread removes this element from the s

我有一个
ConcurrentSKipListSet
,我用
为每个
循环迭代这个集合中的值。
另一个线程在某个时刻将从这个集合中删除一个元素

我想我遇到了这样一种情况:一个线程删除了一个我还没有迭代的元素(或者我刚刚开始迭代),因此从循环中进行的调用失败

为了清晰起见,有一些代码:

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,并且可以与其他操作同时进行

那么这可能吗?如果可能的话,什么是处理这个问题的好方法

谢谢


Will

我也遇到了这个问题,因为队列是由不同的线程写入和读取的。一种方法是标记而不是删除不再需要的元素。在浏览整个列表后,可以运行清理迭代器。您需要一个全局锁,只用于从列表中删除元素,其余时间代码可以并行运行。示意图上它的工作原理如下:

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();
  }
}
我想我遇到了这样一种情况:一个线程删除了一个我还没有迭代的元素(或者我刚刚开始迭代),因此从循环中进行的调用失败

我不认为javadocs是这么说的:

迭代器是弱一致的,返回的元素反映了迭代器创建时或创建之后的某个点的集合状态。它们不会抛出ConcurrentModificationException,并且可以与其他操作同时进行

这意味着您不必担心有人在遍历列表的同时从
ConcurrentSkipListSet
中删除。但是,当您在迭代器中移动时,肯定会出现竞争条件。
foo
在迭代器获得它之后立即被删除,或者它在迭代器之前被删除,但迭代器没有看到它

callService(foo.getId());//这不应该“失败”


如果迭代器返回
foo
,则服务调用不会“失败”,除非它假定
foo
仍在列表中并以某种方式检查它。最糟糕的情况是,您可能会在
foo
上执行一些操作,并使用它调用服务,即使该服务刚刚被另一个线程从列表中删除。

@newuser您能澄清一下吗-reduce是什么意思吗?抱歉,我最近注意到了这个词thread@Will:你说“失败”是什么意思?将尝试此方法:@EnnoShioji服务不喜欢此呼叫-即现在无效。我理解-感谢您的澄清。我的问题是该服务不再希望收到
foo
。我想我需要重新研究服务如何处理这个问题。谢谢