選自《阿里巴巴JAVA開發(fā)手冊》
圖1代碼執(zhí)行情況是:解釋刪除1這個元素不會報(bào)錯,但是刪除2這個元素報(bào)錯了,這個情況如何解釋?
學(xué)習(xí)是最好的投資!
You can know the source of the error from the reported error checkForComodification()
,如果要避免錯誤需要保持 modCount != expectedModCount
為 false
。list.remove(Object)
會去調(diào)用fastRemove(int)
方法,這個時候必然會去修改 modCount
,這個時候就會出現(xiàn)錯誤。Iterator<String> iterator = list.iterator()
;這個方法的實(shí)現(xiàn)就是返回一個內(nèi)部類 Itr
,(迭代的過程都是使用的這個類),但是為什么這個 iterator.remove()
不會出現(xiàn)錯誤了,原因在與這個方法的實(shí)現(xiàn)是在進(jìn)行實(shí)際的 ArrayList.this.remove
之前進(jìn)行的 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
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...
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.
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
Just delete them in reverse order. Anyway, try not to remove the list. You can add delete mark
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.
ArrayList is not thread-safe, which means you modify the List while traversing.
ArrayList will throw a concurrent modification exception in this case.