Many of the containers in Java are modified while they are being traversed, and the elements are concurrentmodificationexception, including multithreading and single-threaded scenarios. Multithreading is the case, the single-threaded occurrence of this exception is generally a traversal (ForEach) in the process of modification caused the state inconsistency in the list, in order to prevent inconsistencies caused unpredictable consequences, so throw an exception. In ArrayList, for example, an internal state check is performed for each operation, as shown in the following code:
Final void checkforcomodification () { if (modcount! = expectedmodcount )throw New concurrentmodificationexception ();
}
When these two values are different, it means that the previous operation has an exception. Where modcount is defined in abstractlist to indicate the number of times the list has been modified. Expectedmodcount is defined in the iterator parent class, and the default value equals Modcount used to represent the desired number of modifications.
But sometimes there is a need to iterate over the changes, such as removing unwanted entries during traversal. This requirement can be fulfilled in a single thread and can be used in the following two ways:
Public voidModifyiterator () {Iterator<String> iterator =List.iterator (); while(Iterator.hasnext ()) {String str=Iterator.next (); if(Str.equals ("") ) Iterator.remove (); } } Public voidModifybyindex () { for(intI=0;i<list.size (); i++) {String str=List.get (i)if(Str.equals ("") ) List.remove (i); } }
Typically, iterator is used, which is not commonly used, and because the element moves after an element is deleted by ArrayList, it will cause an index change and will have an impact on traversal. However, if you use foreach, you will get an error (which is also easy for beginners to make):
Public void Modifyforeach () { for(String str:list) { list.remove (str); } }
If you use the above code, you will get an error. Why would this form be an error? First, take a look at the machine code for the two functions:
Public voidModifyiterator (); Code:0: Aload_01:getfield #17//Field list:ljava/util/list;4:invokeinterface #34, 1//Interfacemethod Java/util/list.iterator: () Ljava/util/iterator;9: Astore_110:Goto19 13: Aload_114:invokeinterface #56, 1//Interfacemethod Java/util/iterator.remove: () V19: Aload_120:invokeinterface #49, 1//Interfacemethod Java/util/iterator.hasnext: () Z25:ifne 13 28:return} Public voidModifyforeach (); Code:0: Aload_01:getfield #17//Field list:ljava/util/list;4:invokeinterface #34, 1//Interfacemethod Java/util/list.iterator: () Ljava/util/iterator;9: astore_210:Goto34 13: Aload_214:invokeinterface #38, 1//Interfacemethod Java/util/iterator.next: () Ljava/lang/object;19:checkcast #44//class Java/lang/string22: Astore_123: Aload_024:getfield #17//Field list:ljava/util/list;27: Aload_128:invokeinterface #46, 2//interfacemethod java/util/list.remove: (ljava/lang/object;) Z33: Pop34: Aload_235:invokeinterface #49, 1//Interfacemethod Java/util/iterator.hasnext: () Z40:ifne 13 43:return
You can see that the traversal process for foreach also uses iterator. But why does the latter make an error? The reason is simple, foreach gets iterator at the beginning, the deletion process does not update the iterator state, so the final state is inconsistent. First, take a look at iterator's delete code:
Public BooleanRemove (Object o) {if(O = =NULL) { for(intindex = 0; index < size; index++) if(Elementdata[index] = =NULL) {fastremove (index); return true; } } Else { for(intindex = 0; index < size; index++) if(O.equals (Elementdata[index])) {fastremove (index); return true; } } return false; } Private voidFastremove (intindex) {Modcount++; intnummoved = size-index-1; if(nummoved > 0) system.arraycopy (elementdata, index+1, Elementdata, Index, nummoved); elementdata[--size] =NULL;//clear to let GC do it work}
The Fastremove method modifies the Modcount, but since iterator has gone back, the expectedmodcount in it has not been updated, resulting in inconsistencies between the two.
Summary: Multi-threaded simultaneous modification of the list or single-threaded using the foreach traversal to modify the list process, many lists will report concurrentmodificationexception errors. This error is due to Expectedmodcount in iterator and Modcount inconsistency in list. Because foreach also uses iterator, but the modification uses a list-related method, iterator does not follow the update. therefore, in the case of multithreading, any operation needs to be synchronized to avoid inconsistent data in the list, and single-threaded traversal modification must use iterator.
Concurrentmodificationexception of the Java list container