ConcurrentModificationException

A small note, the code application written by my colleague before ran fine, but suddenly it fails today, and a java.util.ConcurrentModificationException is reported. Although when I see this exception, I can quickly locate the cause, and the collection is directly in the loop body. Deleted, the following is a small example to simulate the environment at that time:

 

public static void main(String[] args) {

		ArrayList<String> lst = new ArrayList<String>();
		lst.add("a");
		lst.add("b");
		lst.add("c");
		lst.add("d");
		for(String s:lst){
			if(s.equals("c")){
				lst.remove(s);
			}
		}
}

 The above code will not throw any exception when running. If it is changed to s.equals("a") or other "b", "d" will report an error.

 

Let's analyze the reasons: the above for loop, in fact, java still calls Iterator to loop the statement when it is running.

as follows

for(Iterator<String> it = lst.iterator();it.hasNext();){
       String t = it.next();
        if(t.equals("c")){
             lst.remove(t);
        }
}

 So it is easier to debug according to this when looking at it. Looking at the source code, you can see that the iterator() function in the parent class Abstract of ArrayList returns new Itr(), and this Itr is a private inner class that implements Iterator internally.

There are three important properties:

cursor、lastRet、execptrfModCount

when instantiated

	int cursor = 0;
	int lastRet = -1;
	int expectedModCount = modCount;

 

 

modCount is the number of times the original in the record object in the AbstractList was modified.

Back to the example above. At this time expectedModCount = modCount=4; when the loop if is true, that is, cursor=3 at this time when s.equals("c"), after executing lst.remove("c"), size=3 at this time . Let's take a look at the source code of hasNext.

 

	public boolean hasNext() {
            return cursor != size();
	}

	public E next() {
            checkForComodification();
	    try {
		E next = get(cursor);
		lastRet = cursor++;
		return next;
	    } catch (IndexOutOfBoundsException e) {
		checkForComodification();
		throw new NoSuchElementException();
	    }
	}

 At this point, the hasNext() function returns false, and the for loop is exited. The code obviously doesn't throw an error. But if other objects are added to lst, the above exception will occur in the program, and the abnormal point is in the checkForCommodification() function in next.

	final void checkForComodification() {
	    if (modCount != expectedModCount)
		throw new ConcurrentModificationException();
	}
    }

 It is to compare whether modCount is consistent with expectedModCount.

 

But why won't we get an error if we use the iterator's remove?

	public void remove() {
	    if (lastRet == -1)
		throw new IllegalStateException();
            checkForComodification();

	    try {
		AbstractList.this.remove(lastRet);
		if (lastRet < cursor)
		    cursor--;
		lastRet = -1;
		expectedModCount = modCount;
	    } catch (IndexOutOfBoundsException e) {
		throw new ConcurrentModificationException();
	    }
	}

 

Guess you like

Origin http://10.200.1.11:23101/article/api/json?id=326697764&siteId=291194637