【问题标题】:Concurrent modification exception inconsistency [duplicate]并发修改异常不一致[重复]
【发布时间】:2016-05-13 06:25:55
【问题描述】:

如果我取消注释行 list.add("3"),则会引发 ConcurrentModificationException。对于两个元素它工作正常并且对于 1 或 3 个元素抛出异常?对此行为有何解释?

import java.util.*;

public class ConException {

    public static void main(String[] args) {
        List<String> list = new ArrayList<String>();
        list.add("1");
        list.add("2");
        //list.add("3");
        for(String x: list){
            list.remove("1");
        }
        System.out.println(list);
    }
}

【问题讨论】:

  • 如果要删除,请使用索引删除,即 list.remove(list.indexOf(0);
  • @holidayCoder 在这种情况下也不行。
  • @user6328922 查看此链接 - journaldev.com/378/…

标签: java loops


【解决方案1】:

请阅读 ConcurrentModificationException 的 java 文档 https://docs.oracle.com/javase/7/docs/api/java/util/ConcurrentModificationException.html

在您的情况下,只有当您的 ArrayList 中有 2 个元素时,您才不会收到异常,在所有其他情况下,您会收到 ConcurrentModificationException。

正如 javaDoc 所说,它取决于 JRE 确定是否正在进行任何并发修改,并且它不是确定相同修改的保证方法,正如 javadoc 中明确说明的那样。

请注意,通常无法保证快速失败的行为 说,不可能在存在的情况下做出任何硬性保证 不同步的并发修改

【讨论】:

  • 他正在获取字符串数组但删除列表对象,没有得到实际点
【解决方案2】:

您无法在迭代列表时更改列表。
所以你不能在for (String x: list)循环中调用list.remove("1")
删除循环并简单地删除“1”元素。

如果您想删除所有“1”元素,您可以通过以下方式执行此操作:

while (list.remove("1")) {}

编辑:
这是 ArrayListIterator 类的反编译代码,用于 for 循环。每次迭代后调用next方法,其中ConcurrentModificationException可以抛出

private class ArrayListIterator implements Iterator<E> {
    /** Number of elements remaining in this iteration */
    private int remaining = size;

    /** Index of element that remove() would remove, or -1 if no such elt */
    private int removalIndex = -1;

    /** The expected modCount value */
    private int expectedModCount = modCount;

    public boolean hasNext() {
        return remaining != 0;
    }

    @SuppressWarnings("unchecked") public E next() {
        ArrayList<E> ourList = ArrayList.this;
        int rem = remaining;
        if (ourList.modCount != expectedModCount) {
            throw new ConcurrentModificationException();
        }
        if (rem == 0) {
            throw new NoSuchElementException();
        }
        remaining = rem - 1;
        return (E) ourList.array[removalIndex = ourList.size - rem];
    }

    public void remove() {
        Object[] a = array;
        int removalIdx = removalIndex;
        if (modCount != expectedModCount) {
            throw new ConcurrentModificationException();
        }
        if (removalIdx < 0) {
            throw new IllegalStateException();
        }
        System.arraycopy(a, removalIdx + 1, a, removalIdx, remaining);
        a[--size] = null;  // Prevent memory leak
        removalIndex = -1;
        expectedModCount = ++modCount;
    }
}

我们的异常是从next 方法抛出的,条件如下:

if (ourList.modCount != expectedModCount) {
    throw new ConcurrentModificationException();
}

我们的modCount 变量被remove 迭代改变了,所以下一次next 调用将失败。

【讨论】:

  • 怎么样 list.remove(list.indexOf(0)
  • @holidayCoder 有很多可能的解决方案 :) 你的应该可以,但list.remove(0) 会更容易删除第一个元素。
  • 问题不在于删除第一个元素。这就是为什么ConcurrentModificationException 并不总是被抛出。
  • @Artem Mostyaev :我知道我无法更改 for 循环中的列表。那不是问题。有两个元素,当我运行上面的代码时,没有抛出异常。如果列表中有一个或三个元素,则会引发异常。为什么?
  • ConcurrentModificationException 在我们更改循环内的列表时抛出。尝试切换到下一个元素时它会崩溃。所以,如果我们有 2 个元素,我们需要 2 个开关并且不会抛出异常(我不知道 Java 中的确切 for 循环实现)。当我们有 3 个元素时,我们需要 3 个开关,并且崩溃的可能性更高。
猜你喜欢
  • 1970-01-01
  • 2014-03-24
  • 1970-01-01
  • 2012-10-29
  • 1970-01-01
  • 1970-01-01
  • 2016-11-19
相关资源
最近更新 更多