选自《阿里巴巴JAVA开发手册》
图1代码执行情况是:解释删除1这个元素不会报错,但是删除2这个元素报错了,这个情况如何解释?
大家讲道理2017-04-18 10:56:42
You can know the source of the error from the reported error checkForComodification()
,如果要避免错误需要保持 modCount != expectedModCount
为 false
。list.remove(Object)
会去调用fastRemove(int)
方法,这个时候必然会去修改 modCount
,这个时候就会出现错误。Iterator<String> iterator = list.iterator()
;这个方法的实现就是返回一个内部类 Itr
,(迭代的过程都是使用的这个类),但是为什么这个 iterator.remove()
不会出现错误了,原因在与这个方法的实现是在进行实际的 ArrayList.this.remove
之前进行的 checkForComodfication
检查,remove
之后又使 expectedModCount = modCount
, so no error will occur.
Itr.remove
implementation
public void remove() {
if (lastRet < 0)
throw new IllegalStateException();
checkForComodification();
try {
ArrayList.this.remove(lastRet);
cursor = lastRet;
lastRet = -1;
expectedModCount = modCount;
} catch (IndexOutOfBoundsException ex) {
throw new ConcurrentModificationException();
}
}
If there is anything wrong, please point it out @ChaCha哥 @puluyinyi
PHP中文网2017-04-18 10:56:42
In the case of a single thread, when deleting elements when traversing the List, you must use the remove method of Iterator instead of the remove method of List, otherwise a ConcurrentModificationException will occur. Just imagine if a teacher is counting the number of students in the entire class, and if the students don't follow the rules and go out and come in, the teacher will definitely not be able to count them.
In the case of multi-threading, refer to one of my blogs: http://xxgblog.com/2016/04/02...
天蓬老师2017-04-18 10:56:42
First of all, this involves multi-threaded operations. Iterator does not support multi-threaded operations. The List class will maintain a modCount variable internally to record the number of modifications
Example: ArrayList source code
protected transient int modCount = 0;
Every time an Iterator is generated, the Iterator will record the modCount. Each time the next() method is called, the record will be compared with the modCount of the external class List. If it is found to be unequal, a multi-threaded editing exception will be thrown.
Why do you do this? My understanding is that you created an iterator, and the iterator is tightly coupled with the content of the collection to be traversed, which means that the content of the collection corresponding to this iterator is the current content. I definitely don’t want to do it in my bubble sort. When , there are still threads inserting data into my collection, right? So Java uses this simple processing mechanism to prevent the collection from being modified during traversal.
As for why deleting "1" is enough, the reason lies in the hasNext() method of foreach and iterator. The syntactic sugar of foreach is actually
while(itr.hasNext()){
itr.next()
}
So every loop will execute hasNext() first, so take a look at how ArrayList’s hasNext() is written:
public boolean hasNext() {
return cursor != size;
}
cursor is a variable used to mark the position of the iterator. The variable starts from 0, and each time next is called, it performs a +1 operation, so:
After your code deletes "1", size=1, cursor=1, this When hasNext() returns false, the loop ends, so your iterator does not call next to find the second element, so there is no way to detect modCount, so there will be no multi-threaded modification exception
But when you delete "2" , the iterator called next twice. At this time, size=1, cursor=2, and hasNext() returned true, so the iterator foolishly called next() again, which also caused modCount to be unequal and threw Exception for multi-threaded modification.
When your collection has three elements, you will magically find that deleting "1" will throw an exception, but deleting "2" will not be a problem. The reason is that the execution order of the above program is Consistent.
黄舟2017-04-18 10:56:42
Because the number in the collection changes when you add or delete elements, problems may occur when traversing. For example, if a collection has 10 elements, it should be traversed 10 times. When you add Or if an element is deleted, the number of traversals is incorrect, so an error will be reported
PHPz2017-04-18 10:56:42
Just delete them in reverse order. Anyway, try not to remove the list. You can add delete mark
伊谢尔伦2017-04-18 10:56:42
The yellow description in the document is very interesting.
The execution result of this example will be beyond everyone's expectation. So try replacing "1" with "2", will it have the same result?
You still need to look at the source code of ArrayList
, you will know it at a glance.
PHP中文网2017-04-18 10:56:42
ArrayList is not thread-safe, which means you modify the List while traversing.
ArrayList will throw a concurrent modification exception in this case.