【问题标题】:Why check concurrent modifications when iterating thread-unsafe collections?为什么在迭代线程不安全的集合时检查并发修改?
【发布时间】:2020-09-13 01:18:25
【问题描述】:

在同步集合中检查并发修改的快速失败机制是合理的,因为这些集合在多线程环境中被认为是线程安全的,因此它们应该知道并发修改。

但我很困惑,为什么像ArrayList 这样应该在单线程环境中工作的线程不安全集合也需要注意迭代中的并发修改?

感谢您提前回复!

【问题讨论】:

    标签: java concurrency


    【解决方案1】:

    不要将“并发修改”中的“并发”误认为只指多线程。

    您也可以在单线程代码中获得 ConcurrentModificationException:

    List<String> list = new ArrayList<>();
    list.add("");
    Iterator<String> it = list.iterator();
    list.add("");
    it.next(); // ConcurrentModificationException
    

    【讨论】:

    • 请注意,这些机制有时也可以检测到多线程修改,但这并不能保证。更可靠地检测到单个线程中的并发修改(但在一般情况下仍不能保证)。
    • @JoachimSauer 确实如此。如 Javadoc 中所述,CME 表示存在错误,但不存在并不表示不存在错误。
    • 谢谢!但我想知道为什么在创建迭代器后不允许向底层集合添加元素,即使迭代和添加操作在同一个线程中(所以底层集合不应该被破坏)?这是因为迭代应该被视为“原子”操作,即当迭代开始时,底层集合不应该被外部操作更改,无论更改发生在哪个线程
    • @folkboat 这是迭代器应如何处理更改的问题。如果插入是在迭代的当前点之后,将其包含在迭代器返回的元素中显然是正确的吗?如果插入或删除是在迭代器已经通过的地方,那么将迭代器保持在“原处”显然是正确的(就列表中的索引而言;或者就相同的两个元素之间而言)?无论您以何种方式默默地忽略/处理它,它都会有令人惊讶的行为。
    • @folkboat 解释可以在ArrayList的文档中找到:The iterators returned by this class's iterator and listIterator methods are fail-fast [...] 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.
    猜你喜欢
    • 1970-01-01
    • 2011-05-29
    • 1970-01-01
    • 2012-10-17
    • 2011-03-21
    • 1970-01-01
    • 2013-05-13
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多