Why do I get a ConcurrentModificationException?

喜夏-厌秋 提交于 2019-12-04 07:11:06

问题


Why do I get a ConcurrentModificationException at the specified location in my code? I cannot figure out what I am doing wrong... The removeMin() method is being used to locate the min in the list pq, remove it, and return its value

import java.util.Iterator;
import java.util.LinkedList;

public class test1 {

    static LinkedList<Integer> list = new LinkedList<Integer>();

    public static void main(String[] args) {
        list.add(10);
        list.add(4);
        list.add(12);
        list.add(3);
        list.add(7);

        System.out.println(removeMin());
    }

    public static Integer removeMin() {
        LinkedList<Integer> pq = new LinkedList<Integer>();
        Iterator<Integer> itPQ = pq.iterator();

        // Put contents of list into pq
        for (int i = 0; i < list.size(); i++) {
            pq.add(list.removeFirst());
        }

        int min = Integer.MAX_VALUE;
        int pos = 0;
        int remPos = 0;

        while (itPQ.hasNext()) {
            Integer element = itPQ.next(); // I get ConcurrentModificationException here
            if (element < min) {
                min = element;
                remPos = pos;
            }
            pos++;
        }

        pq.remove(remPos);
        return remPos;
    }

}

回答1:


An Iterator should not be considered usable once the Collection from which it was obtained is modified. (This restriction is relaxed for java.util.concurrent.* collection classes.)

You are first obtaining an Iterator for pq, then modifying pq. Once you modify pq, the Iterator itPQ is no longer valid, so when you try to use it, you get a ConcurrentModificationException.

One solution is to move Iterator<Integer> itPQ = pq.iterator(); to right before the while loop. A better approach is to do away with the explicit use of Iterator altogether:

for (Integer element : pq) {

Technically, the for-each loop uses an Iterator internally, so either way, this loop would only be valid as long as you don’t try to modify pq inside the loop.




回答2:


I ran your code, and it turns out that the offending line is here:

Iterator<Integer> itPQ = pq.iterator();

This needs to come after your population of pq, so that the iterator does not have it's data updated asynchronously.

With this modification the code runs.


Now, it does not run correctly. The reason is as @Ishnark pointed out in his answer, that every time you are removing from the list, it gets smaller, and so not all of the list is being added to pq.




回答3:


You face an issue because you added items to pq, using the normal .add() method after you had already created an Iterator for pq. The Iterator doesn't complain when you do the hasNext() because it sees the change in pq.

while (itPQ.hasNext()) {
    ...
    Integer element = itPQ.next(); --> you get exception here
    ...

}

However, it throws an exception when you attempt to iterate through pq. According to this post, "If the iterator detects that some modifications were made without using its method (or using another iterator on the same collection), it cannot guarantee anymore that it will not pass twice on the same element or skip one, so it throws this exception."



来源:https://stackoverflow.com/questions/44445668/why-do-i-get-a-concurrentmodificationexception

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!