There are two types of iterators in Java: fail-safe and fail-fast.
What does this mean, and is the difference between them?
What is the difference between them ...
"Fail-safe" (in engineering) means that something fails in a way that causes no or minimal damage. Strictly speaking, there is no such thing in Java as a fail-safe iterator. If an iterator fails (in the normal sense of "fail"), you can expect damage to occur.
I suspect that you actually mean "weakly consistent" iterators. The javadoc says:
"Most concurrent Collection implementations (including most Queues) also differ from the usual java.util conventions in that their Iterators and Spliterators provide weakly consistent rather than fast-fail traversal."
Typically, weak consistency means that if a collection is modified concurrently with an iteration, the guarantees of what the iteration sees are weaker. (The details will be specified in each concurrent collection classes javadocs.)
"Fail-fast" (in systems design) means that the failure condition is checked aggressively so that the failure condition is (where possible1) detected before too much damage can be done. In Java, a fail-fast iterator fails by throwing a ConcurrentModificationException.
The alternative to "fail-fast" and "weakly consistent" is semantic where the iteration fails unpredictably; e.g. to sometimes give the wrong answer or throw an unexpected exception. (This was the behavior of some standard implementations of the Enumeration API in early versions of Java.)
... and are they different from the iterator we use for collection.
No. These are properties of the iterators implemented by standard Collection types; i.e. they are either "fail fast" or "weakly consistent" ... when used correctly with respect to synchronization and the Java memory model1.
Fail-fast iterators are typically implemented using a volatile counter on the collection object.
When the collection is updated, the counter is incremented.
When an Iterator is created, the current value of the counter is embedded in the Iterator object.
When an Iterator operation is performed, the method compares the two counter values and throws a CME if they are different.
By contrast, weakly consistent iterators are typically light-weight and leverage properties of each concurrent collection's internal data structures. There is no general pattern. If you are interested, read the source code for different collection classes.
1 - The rider is that fail-fast iterator behavior assumes that the application is correctly implemented with respect to synchronization and the memory model. (In other words, the application is thread-safe.) For example, if you iterated an ArrayList without proper synchronization, the "fast fail" mechanism should detect the concurrent modification (though that isn't guaranteed), but may not prevent the list from being corrupted due to the application's unsafe behavior. To illustrate, the javadoc for Vector.iterator() says this:
"The fail-fast behavior of an iterator cannot be guaranteed as it is, generally speaking, impossible to make any hard guarantees in the presence of unsynchronized concurrent modification. Fail-fast iterators throw ConcurrentModificationException on a best-effort basis. Therefore, it would be wrong to write a program that depended on this exception for its correctness: the fail-fast behavior of iterators should be used only to detect bugs."
They are rather fail-fast and weakly-consistent types:
Iterators from java.util package throw ConcurrentModificationException if collection was modified by collection's methods (add / remove) while iterating
Iterators from java.util.concurrent package typically iterate over a snapshot and allow concurrent modifications but may not reflect collection updates after the iterator was created.
The only difference is fail-safe iterator doesn't throw any Exception, contrary to fail-fast Iterator.
If Collection is modified structurally while one thread is iterating over it. This is because they work on clone of Collection instead of original collection and that’s why they are called as fail-safe iterator.
Iterator of CopyOnWriteArrayList is an example of fail-safe Iterator also iterator written by ConcurrentHashMap keySet is also fail-safe iterator and never throw ConcurrentModificationException in Java.
This scenario relate with "concurrent processing", means that more then one user accessing the same resource. In such situation, one of the user try to modify that resource which cause the 'ConcurrentProcessingException' because in that case other user get improper data. Both this type relate with this kind of situation.
In simple term,
Fail-Fast :
Iterators immediately throw ConcurrentModificationException if structural modification(add, update, delete) happens.
Example : ArrayList, HashMap, TreeSet
Fail-Safe :
Here Iterators not throw any exception because they operate on the clone of the collection, not original one. So, that they are fail-safe iterators.
Example : CopyOnWriteArrayList, ConcurrentHashMap
Related
I am using a Collection (a HashMap used indirectly by the JPA, it so happens), but apparently randomly the code throws a ConcurrentModificationException. What is causing it and how do I fix this problem? By using some synchronization, perhaps?
Here is the full stack-trace:
Exception in thread "pool-1-thread-1" java.util.ConcurrentModificationException
at java.util.HashMap$HashIterator.nextEntry(Unknown Source)
at java.util.HashMap$ValueIterator.next(Unknown Source)
at org.hibernate.collection.AbstractPersistentCollection$IteratorProxy.next(AbstractPersistentCollection.java:555)
at org.hibernate.engine.Cascade.cascadeCollectionElements(Cascade.java:296)
at org.hibernate.engine.Cascade.cascadeCollection(Cascade.java:242)
at org.hibernate.engine.Cascade.cascadeAssociation(Cascade.java:219)
at org.hibernate.engine.Cascade.cascadeProperty(Cascade.java:169)
at org.hibernate.engine.Cascade.cascade(Cascade.java:130)
This is not a synchronization problem. This will occur if the underlying collection that is being iterated over is modified by anything other than the Iterator itself.
Iterator it = map.entrySet().iterator();
while (it.hasNext()) {
Entry item = it.next();
map.remove(item.getKey());
}
This will throw a ConcurrentModificationException when the it.hasNext() is called the second time.
The correct approach would be
Iterator it = map.entrySet().iterator();
while (it.hasNext()) {
Entry item = it.next();
it.remove();
}
Assuming this iterator supports the remove() operation.
Try using a ConcurrentHashMap instead of a plain HashMap
Modification of a Collection while iterating through that Collection using an Iterator is not permitted by most of the Collection classes. The Java library calls an attempt to modify a Collection while iterating through it a "concurrent modification". That unfortunately suggests the only possible cause is simultaneous modification by multiple threads, but that is not so. Using only one thread it is possible to create an iterator for the Collection (using Collection.iterator(), or an enhanced for loop), start iterating (using Iterator.next(), or equivalently entering the body of the enhanced for loop), modify the Collection, then continue iterating.
To help programmers, some implementations of those Collection classes attempt to detect erroneous concurrent modification, and throw a ConcurrentModificationException if they detect it. However, it is in general not possible and practical to guarantee detection of all concurrent modifications. So erroneous use of the Collection does not always result in a thrown ConcurrentModificationException.
The documentation of ConcurrentModificationException says:
This exception may be thrown by methods that have detected concurrent modification of an object when such modification is not permissible...
Note that this exception does not always indicate that an object has been concurrently modified by a different thread. If a single thread issues a sequence of method invocations that violates the contract of an object, the object may throw this exception...
Note that fail-fast behavior cannot be guaranteed as it is, generally speaking, impossible to make any hard guarantees in the presence of unsynchronized concurrent modification. Fail-fast operations throw ConcurrentModificationException on a best-effort basis.
Note that
the exception may be throw, not must be thrown
different threads are not required
throwing the exception cannot be guaranteed
throwing the exception is on a best-effort basis
throwing the exception happens when the concurrent modification is detected, not when it is caused
The documentation of the HashSet, HashMap, TreeSet and ArrayList classes says this:
The iterators returned [directly or indirectly from this class] are fail-fast: if the [collection] is modified at any time after the iterator is created, in any way except through the iterator's own remove method, the Iterator throws a ConcurrentModificationException. Thus, in the face of concurrent modification, the iterator fails quickly and cleanly, rather than risking arbitrary, non-deterministic behavior at an undetermined time in the future.
Note that the fail-fast behavior of an iterator cannot be guaranteed as it is, generally speaking, impossible to make any hard guarantees in the presence of unsynchronized concurrent modification. Fail-fast iterators throw ConcurrentModificationException on a best-effort basis. Therefore, it would be wrong to write a program that depended on this exception for its correctness: the fail-fast behavior of iterators should be used only to detect bugs.
Note again that the behaviour "cannot be guaranteed" and is only "on a best-effort basis".
The documentation of several methods of the Map interface say this:
Non-concurrent implementations should override this method and, on a best-effort basis, throw a ConcurrentModificationException if it is detected that the mapping function modifies this map during computation. Concurrent implementations should override this method and, on a best-effort basis, throw an IllegalStateException if it is detected that the mapping function modifies this map during computation and as a result computation would never complete.
Note again that only a "best-effort basis" is required for detection, and a ConcurrentModificationException is explicitly suggested only for the non concurrent (non thread-safe) classes.
Debugging ConcurrentModificationException
So, when you see a stack-trace due to a ConcurrentModificationException, you can not immediately assume that the cause is unsafe multi-threaded access to a Collection. You must examine the stack-trace to determine which class of Collection threw the exception (a method of the class will have directly or indirectly thrown it), and for which Collection object. Then you must examine from where that object can be modified.
The most common cause is modification of the Collection within an enhanced for loop over the Collection. Just because you do not see an Iterator object in your source code does not mean there is no Iterator there! Fortunately, one of the statements of the faulty for loop will usually be in the stack-trace, so tracking down the error is usually easy.
A trickier case is when your code passes around references to the Collection object. Note that unmodifiable views of collections (such as produced by Collections.unmodifiableList()) retain a reference to the modifiable collection, so iteration over an "unmodifiable" collection can throw the exception (the modification has been done elsewhere). Other views of your Collection, such as sub lists, Map entry sets and Map key sets also retain references to the original (modifiable) Collection. This can be a problem even for a thread-safe Collection, such as CopyOnWriteList; do not assume that thread-safe (concurrent) collections can never throw the exception.
Which operations can modify a Collection can be unexpected in some cases. For example, LinkedHashMap.get() modifies its collection.
The hardest cases are when the exception is due to concurrent modification by multiple threads.
Programming to prevent concurrent modification errors
When possible, confine all references to a Collection object, so its is easier to prevent concurrent modifications. Make the Collection a private object or a local variable, and do not return references to the Collection or its iterators from methods. It is then much easier to examine all the places where the Collection can be modified. If the Collection is to be used by multiple threads, it is then practical to ensure that the threads access the Collection only with appropriate synchonization and locking.
In Java 8, you can use lambda expression:
map.keySet().removeIf(key -> key condition);
removeIf is a convenient default method in Collection which uses Iterator internally to iterate over the elements of the calling collection.
The extraction of the removal condition is expressed by allowing the caller to provide a Predicate<? super E>.
"I'll perform the iteration for you and test your Predicate on each one of the elements in the collection. If an element causes the test method of the Predicate to return true, I'll remove it."
It sounds less like a Java synchronization issue and more like a database locking problem.
I don't know if adding a version to all your persistent classes will sort it out, but that's one way that Hibernate can provide exclusive access to rows in a table.
Could be that isolation level needs to be higher. If you allow "dirty reads", maybe you need to bump up to serializable.
Note that the selected answer cannot be applied to your context directly before some modification, if you are trying to remove some entries from the map while iterating the map just like me.
I just give my working example here for newbies to save their time:
HashMap<Character,Integer> map=new HashMap();
//adding some entries to the map
...
int threshold;
//initialize the threshold
...
Iterator it=map.entrySet().iterator();
while(it.hasNext()){
Map.Entry<Character,Integer> item=(Map.Entry<Character,Integer>)it.next();
//it.remove() will delete the item from the map
if((Integer)item.getValue()<threshold){
it.remove();
}
Try either CopyOnWriteArrayList or CopyOnWriteArraySet depending on what you are trying to do.
I ran into this exception when try to remove x last items from list.
myList.subList(lastIndex, myList.size()).clear(); was the only solution that worked for me.
A ConcurrentModificationException was returned removing an entry from a map but I am unable to see what's wrong.
Iterator<String> mapIterator = this.attributeMap.keySet().iterator();
while (mapIterator.hasNext())
{
String attributeName = mapIterator.next();
if (attributeName.matches(pattern))
{
mapIterator.remove();
}
}
In this case the line
mapIterator.next()
throws ConcurrentModificationException .
The reason behind this is:
There is an int variable modCount which provides the number of times list size has been changed, this value is used in every next() call to check for any modifications in a function checkForComodification(). if mapIterator.next() found change in modCount while iteration object then it will throw ConcurrentModificationException .
To avoid this please follow the below points:
You can convert the list to an array and then iterate on the array. This approach works well for small or medium size list but if the list is large then it will affect the performance a lot.
You can lock the list while iterating by putting it in a synchronized block. This approach is not recommended because it will cease the benefits of multithreading.
If you are using JDK1.5 or higher then you can use ConcurrentHashMap and CopyOnWriteArrayList classes. It is the recommended approach.
You can check this out on some details about CME: https://docs.oracle.com/javase/7/docs/api/java/util/ConcurrentModificationException.html
This exception may be thrown by methods that have detected concurrent modification of an object when such modification is not permissible.
For example, it is not generally permissible for one thread to modify a Collection while another thread is iterating over it. In general, the results of the iteration are undefined under these circumstances. Some Iterator implementations (including those of all the general purpose collection implementations provided by the JRE) may choose to throw this exception if this behavior is detected. Iterators that do this are known as fail-fast iterators, as they fail quickly and cleanly, rather that risking arbitrary, non-deterministic behavior at an undetermined time in the future.
Here are some solutions provided by Baeldung, linked below:
Using an Iterator Directly
Not removing during iteration
Using removeIf()
Filtering using Streams
You can check his site out for the details for each solution to avoid CME: https://www.baeldung.com/java-concurrentmodificationexception
Hope this helps.
I want to remove all items from someMap which keys are not present in someList.
Take a look into my code:
someMap.keySet()
.stream()
.filter(v -> !someList.contains(v))
.forEach(someMap::remove);
I receive java.util.ConcurrentModificationException.
Why I faced this Exception given that the stream is not parallel?
What is the most elegant way to do this?
#Eran already explained how to solve this problem better. I will explain why ConcurrentModificationException occurs.
The ConcurrentModificationException occurs because you are modifying the stream source. Your Map is likely to be HashMap or TreeMap or other non-concurrent map. Let's assume it's a HashMap. Every stream is backed by Spliterator. If spliterator has no IMMUTABLE and CONCURRENT characteristics, then, as documentation says:
After binding a Spliterator should, on a best-effort basis, throw ConcurrentModificationException if structural interference is detected. Spliterators that do this are called fail-fast.
So the HashMap.keySet().spliterator() is not IMMUTABLE (because this Set can be modified) and not CONCURRENT (concurrent updates are unsafe for HashMap). So it just detects the concurrent changes and throws a ConcurrentModificationException as spliterator documentation prescribes.
Also it worth citing the HashMap documentation:
The iterators returned by all of this class's "collection view methods" are fail-fast: if the map is structurally modified at any time after the iterator is created, in any way except through the iterator's own remove method, the iterator will throw a ConcurrentModificationException. Thus, in the face of concurrent modification, the iterator fails quickly and cleanly, rather than risking arbitrary, non-deterministic behavior at an undetermined time in the future.
Note that the fail-fast behavior of an iterator cannot be guaranteed as it is, generally speaking, impossible to make any hard guarantees in the presence of unsynchronized concurrent modification. Fail-fast iterators throw ConcurrentModificationException on a best-effort basis. Therefore, it would be wrong to write a program that depended on this exception for its correctness: the fail-fast behavior of iterators should be used only to detect bugs.
While it says about iterators only, I believe it's the same for spliterators.
You don't need the Stream API for that. Use retainAll on the keySet. Any changes on the Set returned by keySet() are reflected in the original Map.
someMap.keySet().retainAll(someList);
Your stream call is (logically) doing the same as:
for (K k : someMap.keySet()) {
if (!someList.contains(k)) {
someMap.remove(k);
}
}
If you run this, you will find it throws ConcurrentModificationException, because it is modifying the map at the same time as you're iterating over it. If you have a look at the docs, you'll notice the following:
Note that this exception does not always indicate that an object has been concurrently modified by a different thread. If a single thread issues a sequence of method invocations that violates the contract of an object, the object may throw this exception. For example, if a thread modifies a collection directly while it is iterating over the collection with a fail-fast iterator, the iterator will throw this exception.
This is what you are doing, the map implementation you're using evidently has fail-fast iterators, therefore this exception is being thrown.
One possible alternative is to remove the items using the iterator directly:
for (Iterator<K> ks = someMap.keySet().iterator(); ks.hasNext(); ) {
K next = ks.next();
if (!someList.contains(k)) {
ks.remove();
}
}
Later answer, but you could insert a collector into your pipeline so that forEach is operating on a Set which holds a copy of the keys:
someMap.keySet()
.stream()
.filter(v -> !someList.contains(v))
.collect(Collectors.toSet())
.forEach(someMap::remove);
I want to remove all items from someMap which keys are not present in someList.
Take a look into my code:
someMap.keySet()
.stream()
.filter(v -> !someList.contains(v))
.forEach(someMap::remove);
I receive java.util.ConcurrentModificationException.
Why I faced this Exception given that the stream is not parallel?
What is the most elegant way to do this?
#Eran already explained how to solve this problem better. I will explain why ConcurrentModificationException occurs.
The ConcurrentModificationException occurs because you are modifying the stream source. Your Map is likely to be HashMap or TreeMap or other non-concurrent map. Let's assume it's a HashMap. Every stream is backed by Spliterator. If spliterator has no IMMUTABLE and CONCURRENT characteristics, then, as documentation says:
After binding a Spliterator should, on a best-effort basis, throw ConcurrentModificationException if structural interference is detected. Spliterators that do this are called fail-fast.
So the HashMap.keySet().spliterator() is not IMMUTABLE (because this Set can be modified) and not CONCURRENT (concurrent updates are unsafe for HashMap). So it just detects the concurrent changes and throws a ConcurrentModificationException as spliterator documentation prescribes.
Also it worth citing the HashMap documentation:
The iterators returned by all of this class's "collection view methods" are fail-fast: if the map is structurally modified at any time after the iterator is created, in any way except through the iterator's own remove method, the iterator will throw a ConcurrentModificationException. Thus, in the face of concurrent modification, the iterator fails quickly and cleanly, rather than risking arbitrary, non-deterministic behavior at an undetermined time in the future.
Note that the fail-fast behavior of an iterator cannot be guaranteed as it is, generally speaking, impossible to make any hard guarantees in the presence of unsynchronized concurrent modification. Fail-fast iterators throw ConcurrentModificationException on a best-effort basis. Therefore, it would be wrong to write a program that depended on this exception for its correctness: the fail-fast behavior of iterators should be used only to detect bugs.
While it says about iterators only, I believe it's the same for spliterators.
You don't need the Stream API for that. Use retainAll on the keySet. Any changes on the Set returned by keySet() are reflected in the original Map.
someMap.keySet().retainAll(someList);
Your stream call is (logically) doing the same as:
for (K k : someMap.keySet()) {
if (!someList.contains(k)) {
someMap.remove(k);
}
}
If you run this, you will find it throws ConcurrentModificationException, because it is modifying the map at the same time as you're iterating over it. If you have a look at the docs, you'll notice the following:
Note that this exception does not always indicate that an object has been concurrently modified by a different thread. If a single thread issues a sequence of method invocations that violates the contract of an object, the object may throw this exception. For example, if a thread modifies a collection directly while it is iterating over the collection with a fail-fast iterator, the iterator will throw this exception.
This is what you are doing, the map implementation you're using evidently has fail-fast iterators, therefore this exception is being thrown.
One possible alternative is to remove the items using the iterator directly:
for (Iterator<K> ks = someMap.keySet().iterator(); ks.hasNext(); ) {
K next = ks.next();
if (!someList.contains(k)) {
ks.remove();
}
}
Later answer, but you could insert a collector into your pipeline so that forEach is operating on a Set which holds a copy of the keys:
someMap.keySet()
.stream()
.filter(v -> !someList.contains(v))
.collect(Collectors.toSet())
.forEach(someMap::remove);
final Multimap<Term, BooleanClause> terms = getTerms(bq);
for (Term t : terms.keySet()) {
Collection<BooleanClause> C = new HashSet(terms.get(t));
if (!C.isEmpty()) {
for (Iterator<BooleanClause> it = C.iterator(); it.hasNext();) {
BooleanClause c = it.next();
if(c.isSomething()) C.remove(c);
}
}
}
Not a SSCCE, but can you pick up the smell?
The Iterator for the HashSet class is a fail-fast iterator. From the documentation of the HashSet class:
The iterators returned by this class's iterator method are fail-fast:
if the set is modified at any time after the iterator is created, in
any way except through the iterator's own remove method, the Iterator
throws a ConcurrentModificationException. Thus, in the face of
concurrent modification, the iterator fails quickly and cleanly,
rather than risking arbitrary, non-deterministic behavior at an
undetermined time in the future.
Note that the fail-fast behavior of an iterator cannot be guaranteed
as it is, generally speaking, impossible to make any hard guarantees
in the presence of unsynchronized concurrent modification. Fail-fast
iterators throw ConcurrentModificationException on a best-effort
basis. Therefore, it would be wrong to write a program that depended
on this exception for its correctness: the fail-fast behavior of
iterators should be used only to detect bugs.
Note the last sentence - the fact that you are catching a ConcurrentModificationException implies that another thread is modifying the collection. The same Javadoc API page also states:
If multiple threads access a hash set concurrently, and at least one
of the threads modifies the set, it must be synchronized externally.
This is typically accomplished by synchronizing on some object that
naturally encapsulates the set. If no such object exists, the set
should be "wrapped" using the Collections.synchronizedSet method. This
is best done at creation time, to prevent accidental unsynchronized
access to the set:
Set s = Collections.synchronizedSet(new HashSet(...));
I believe the references to the Javadoc are self explanatory in what ought to be done next.
Additionally, in your case, I do not see why you are not using the ImmutableSet, instead of creating a HashSet on the terms object (which could possibly be modified in the interim; I cannot see the implementation of the getTerms method, but I have a hunch that the underlying keyset is being modified). Creating a immutable set will allow the current thread to have it's own defensive copy of the original key-set.
Note, that although a ConcurrentModificationException can be prevented by using a synchronized Set (as noted in the Java API documentation), it is a prerequisite that all threads access the synchronized collection and not the backing collection directly (which might be untrue in your case as the HashSet is probably created in one thread, while the underlying collection for the MultiMap is modified by other threads). The synchronized collection classes actually maintain an internal mutex for threads to acquire access to; since you cannot access the mutex directly from other threads (and it would be quite ridiculous to do so here), you ought to look at using a defensive copy of either the keyset or of the MultiMap itself using the unmodifiableMultimap method of the MultiMaps class (you'll need to return an unmodifiable MultiMap from the getTerms method). You could also investigate the necessity of returning a synchronized MultiMap, but then again, you'll need to ensure that the mutex must be acquired by any thread to protect the underlying collection from concurrent modifications.
Note, I have deliberately omitted mentioning the use of a thread-safe HashSet for the sole reason that I'm unsure of whether concurrent access to the actual collection will be ensured; it most likely will not be the case.
Edit: ConcurrentModificationExceptions thrown on Iterator.next in a single-threaded scenario
This is with respect to the statement: if(c.isSomething()) C.remove(c); that was introduced in the edited question.
Invoking Collection.remove changes the nature of the question, for it now becomes possible to have ConcurrentModificationExceptions thrown even in a single-threaded scenario.
The possibility arises out of the use of the method itself, in conjunction with the use of the Collection's iterator, in this case the variable it that was initialized using the statement : Iterator<BooleanClause> it = C.iterator();.
The Iterator it that iterates over Collection C stores state pertinent to the current state of the Collection. In this particular case (assuming a Sun/Oracle JRE), a KeyIterator (an internal inner class of the HashMap class that is used by the HashSet) is used to iterate through the Collection. A particular characteristic of this Iterator is that it tracks the number of structural modifications performed on the Collection (the HashMap in this case) via it's Iterator.remove method.
When you invoke remove on the Collection directly, and then follow it up with an invocation of Iterator.next, the iterator throws a ConcurrentModificationException, as Iterator.next verifies whether any structural modifications of the Collection have occurred that the Iterator is unaware of. In this case, Collection.remove causes a structural modification, that is tracked by the Collection, but not by the Iterator.
To overcome this part of the problem, you must invoke Iterator.remove and not Collection.remove, for this ensures that the Iterator is now aware of the modification to the Collection. The Iterator in this case, will track the structural modification occurring through the remove method. Your code should therefore look like the following:
final Multimap<Term, BooleanClause> terms = getTerms(bq);
for (Term t : terms.keySet()) {
Collection<BooleanClause> C = new HashSet(terms.get(t));
if (!C.isEmpty()) {
for (Iterator<BooleanClause> it = C.iterator(); it.hasNext();) {
BooleanClause c = it.next();
if(c.isSomething()) it.remove(); // <-- invoke remove on the Iterator. Removes the element returned by it.next.
}
}
}
The reason is that you are trying to modify the collection outside iterator.
How it works :
When you create an iterator the collection maintains a modificationNum-variable for both the collection and the iterator independently.
1. The variable for collection is being incremented for each change made to the collection and and iterator.
2. The variable for iterator is being incremented for each change made to the iterator.
So when you call it.remove() through iterator that increases the value of both the modification-number-variable by 1.
But again when you call collection.remove() on collection directly, that increments only the value of the modification-numbervariable for the collection, but not the variable for the iterator.
And rule is : whenever the modification-number value for the iterator does not match with the original collection modification-number value, it gives ConcurrentModificationException.
Vineet Reynolds has explained in great details the reasons why collections throw a ConcurrentModificationException (thread-safety, concurrency). Swagatika has explained in great details the implementation details of this mechanism (how collection and iterator keep count of the number of modifications).
Their answers were interesting, and I upvoted them. But, in your case, the problem does not come from concurrency (you have only one thread), and implementation details, while interesting, should not be considered here.
You should only consider this part of the HashSet javadoc:
The iterators returned by this class's iterator method are fail-fast:
if the set is modified at any time after the iterator is created, in
any way except through the iterator's own remove method, the Iterator
throws a ConcurrentModificationException. Thus, in the face of
concurrent modification, the iterator fails quickly and cleanly,
rather than risking arbitrary, non-deterministic behavior at an
undetermined time in the future.
In your code, you iterate over your HashSet using its iterator, but you use the HashSet's own remove method to remove elements ( C.remove(c) ), which causes the ConcurrentModificationException. Instead, as explained in the javadoc, you should use the Iterator's own remove() method, which removes the element being currently iterated from the underlying collection.
Replace
if(c.isSomething()) C.remove(c);
with
if(c.isSomething()) it.remove();
If you want to use a more functional approach, you could create a Predicate and use Guava's Iterables.removeIf() method on the HashSet:
Predicate<BooleanClause> ignoredBooleanClausePredicate = ...;
Multimap<Term, BooleanClause> terms = getTerms(bq);
for (Term term : terms.keySet()) {
Collection<BooleanClause> booleanClauses = Sets.newHashSet(terms.get(term));
Iterables.removeIf(booleanClauses, ignoredBooleanClausePredicate);
}
PS: note that in both cases, this will only remove elements from the temporary HashSet. The Multimap won't be modified.