为什么 ArrayList 从多线程修改时不抛出 ConcurrentModificationException? [英] Why does ArrayList not throw ConcurrentModificationException when modified from multiple threads?

查看:22
本文介绍了为什么 ArrayList 从多线程修改时不抛出 ConcurrentModificationException?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

ConcurrentModificationException :当不允许此类修改时,检测到对象的并发修改的方法可能会抛出此异常.

ConcurrentModificationException : This exception may be thrown by methods that have detected concurrent modification of an object when such modification is not permissible.

以上是 javadoc 中的 ConcurrentModificationException 定义.

Above is ConcurrentModificationException definition from javadoc.

所以我尝试测试以下代码:

So I try to test below code:

final List<String> tickets = new ArrayList<String>(100000);
for (int i = 0; i < 100000; i++) {
    tickets.add("ticket NO," + i);
}
for (int i = 0; i < 10; i++) {
    Thread salethread = new Thread() {
        public void run() {
            while (tickets.size() > 0) {
                tickets.remove(0);
                System.out.println(Thread.currentThread().getId()+"Remove 0");
            }
        }
    };
    salethread.start();
}

代码很简单.10 个线程从 arraylist 对象中删除元素.确保多个线程访问一个对象.但它运行正常.不会抛出异常.为什么?

The code is simple. 10 threads remove the element from the arraylist object. It is sure that multiple threads access one object. But it runs OK. No exception is thrown. Why?

推荐答案

我引用了 ArrayList Javadoc 为您服务.突出显示了解释您所看到的行为的相关部分.

I'm quoting a large section of the ArrayList Javadoc for your benefit. Relevant portions that explain the behavior you are seeing are highlighted.

请注意,此实现不是同步的.如果多个线程同时访问一个 ArrayList 实例,并且至少有一个线程在结构上修改列表,它必须是同步的外部.(结构修改是任何增加或删除一个或多个元素,或显式调整后备数组的大小;仅仅设置元素的值不是结构性的修改.)这通常是通过同步一些自然封装列表的对象.如果不存在这样的对象,该列表应该使用 Collections.synchronizedList 进行包装"方法.这最好在创建时完成,以防止意外对列表的非同步访问:

Note that this implementation is not synchronized. If multiple threads access an ArrayList instance concurrently, and at least one of the threads modifies the list structurally, it must be synchronized externally. (A structural modification is any operation that adds or deletes one or more elements, or explicitly resizes the backing array; merely setting the value of an element is not a structural modification.) This is typically accomplished by synchronizing on some object that naturally encapsulates the list. If no such object exists, the list should be "wrapped" using the Collections.synchronizedList method. This is best done at creation time, to prevent accidental unsynchronized access to the list:

List list = Collections.synchronizedList(new ArrayList(...));

List list = Collections.synchronizedList(new ArrayList(...));

该类的 iterator 和 listIterator 方法返回的迭代器快速失败:如果列表在之后的任何时间进行了结构修改迭代器以任何方式创建,除了通过迭代器自己的删除或添加方法,迭代器将抛出一个并发修改异常.因此,面对并发修改,迭代器快速而干净地失败,而不是在不确定的时间冒着任意的、不确定的行为的风险未来.

The iterators returned by this class's iterator and listIterator methods are fail-fast: if the list is structurally modified at any time after the iterator is created, in any way except through the iterator's own remove or add methods, the iterator will throw a ConcurrentModificationException. Thus, in the face of concurrent modification, the iterator fails quickly and cleanly, rather than risking arbitrary, non-deterministic behavior at an undetermined time in the future.

请注意,不能保证迭代器的快速失败行为因为一般来说,不可能做出任何硬性保证存在不同步的并发修改.快速失败迭代器尽最大努力抛出 ConcurrentModificationException基础.因此,编写一个依赖的程序是错误的关于这个例外的正确性:fail-fast 行为迭代器应该只用于检测错误.

Note that the fail-fast behavior of an iterator cannot be guaranteed as it is, generally speaking, impossible to make any hard guarantees in the presence of unsynchronized concurrent modification. Fail-fast iterators throw ConcurrentModificationException on a best-effort basis. Therefore, it would be wrong to write a program that depended on this exception for its correctness: the fail-fast behavior of iterators should be used only to detect bugs.

ArrayLists 通常会抛出并发修改异常,如果你在结构上修改列表同时通过它的迭代器访问它(但即使这也不是绝对的保证).请注意,在您的示例中,您是直接从列表中删除元素,而不是使用迭代器.

ArrayLists will generally throw concurrent modification exceptions if you modify the list structurally while accessing it through its iterator (but even this is not an absolute guarantee). Note that in your example you are removing elements from the list directly, and you are not using an iterator.

如果你喜欢,还可以浏览ArrayList.remove,以更好地了解其工作原理.

If it tickles your fancy, you can also browse the implementation of ArrayList.remove, to get a better understanding of how it works.

这篇关于为什么 ArrayList 从多线程修改时不抛出 ConcurrentModificationException?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆