Search code examples
javamultithreadingsetjava.util.concurrent

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. 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.

So is this possible, and if so, what's a good way of handling this?

Thanks

Will


Solution

  • 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:

    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.

    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. 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.

    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. 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.