-
CSR
-
Resolution: Unresolved
-
P4
-
None
-
behavioral
-
minimal
-
Unlikely that anyone is depending on ConcurrentModificationExceptions being thrown
-
Java API
Summary
ArrayList.replaceAll and Vector.replaceAll should not modify modCount, since they are not "structural modifications".
Problem
ArrayList#replaceAll increments modCount, but ArrayList subList#replaceAll does not.
Vector#replaceAll increments modCount, but Vector subList#replaceAll (inherited from AbstractList and List) does not.
ArrayList#replaceAll increments modCount, but the analogous HashMap#replaceAll does not.
List#replaceAll is specified and implemented in terms of List#set, which does not modify modCount in any implementation.
The List spec could be clearer, but the intent is that only operations that cause an object to "lose its place" in the List (modify its index) should cause ConcurrentModificationException. So element insertion and deletion cause ConcurrentModificationException, but replacing an element via List#set or ListIterator#set does not. Method replaceAll is logically just a call to List#set on every element, and the default implementation in List#replaceAll in fact does call List#set. "Structural modification" is a property that does compose over a series of operations.
There are valid uses of replaceAll that should not break concurrent readers, e.g. a periodic call to Vector.replaceAll(x -> optimized(x)). In such a scenario incrementing modCount introduces a rare race instead of detecting one.
The List interface is concurrency-hostile precisely because the mapping from index to element can change. But if a List is used in such a way that this cannot happen, array-style (like AtomicReferenceArray), then concurrent use becomes quite reasonable. Especially if there is only one writer thread.
Solution
Remove modCount++ statements in the source code.
Specification
No spec changes, although the existing spec for modCount and "structural modification" could be improved in a separate effort (JDK-8203663).
- csr of
-
JDK-8203662 remove increment of modCount from ArrayList and Vector replaceAll()
-
- Open
-
- relates to
-
JDK-8340572 ConcurrentModificationException when sorting ArrayList sublists
-
- Closed
-
-
JDK-8203663 adjust ConcurrentModificationException policies and specifications
-
- Open
-