当前位置: 首页 > 面试题库 >

集合根据集合的内容引发或不引发ConcurrentModificationException

艾学海
2023-03-14
问题内容

以下Java代码ConcurrentModificationException按预期抛出:

public class Evil
{
    public static void main(String[] args) {
        Collection<String> c = new ArrayList<String>();
        c.add("lalala");
        c.add("sososo");
        c.add("ahaaha");
        removeLalala(c);
        System.err.println(c);
    }
    private static void removeLalala(Collection<String> c) 
    {
        for (Iterator<String> i = c.iterator(); i.hasNext();) {
            String s = i.next();
            if(s.equals("lalala")) {
                c.remove(s);
            }
        }
    }
}

但是以下示例仅在的内容上有所不同Collection,执行时没有任何例外:

public class Evil {
    public static void main(String[] args) 
    {
        Collection<String> c = new ArrayList<String>();
        c.add("lalala");
        c.add("lalala");
        removeLalala(c);
        System.err.println(c);
    }
    private static void removeLalala(Collection<String> c) {
        for (Iterator<String> i = c.iterator(); i.hasNext();) {
            String s = i.next();
            if(s.equals("lalala")) {
                c.remove(s);
            }
        }
    }
}

打印输出“ [lalala]”。为什么ConcurrentModificationException在第一个示例执行时第二个示例却不抛出?


问题答案:

简短答案

因为不能保证迭代器的快速失败行为。

长答案

之所以会出现此异常,是因为除非通过迭代器,否则无法在迭代集合时操作集合

坏:

// we're using iterator
for (Iterator<String> i = c.iterator(); i.hasNext();) {  
    // here, the collection will check it hasn't been modified (in effort to fail fast)
    String s = i.next();
    if(s.equals("lalala")) {
        // s is removed from the collection and the collection will take note it was modified
        c.remove(s);
    }
}

好:

// we're using iterator
for (Iterator<String> i = c.iterator(); i.hasNext();) {  
    // here, the collection will check it hasn't been modified (in effort to fail fast)
    String s = i.next();
    if(s.equals("lalala")) {
        // s is removed from the collection through iterator, so the iterator knows the collection changed and can resume the iteration
        i.remove();
    }
}

现在转到“为什么”:在上面的代码中,请注意如何执行修改检查-
删除操作将集合标记为已修改,并且下一次迭代检查所有修改,如果检测到集合已更改,则失败。另一个重要的事情是,ArrayList(不知道其他收藏品),并
不能 为您在修改hasNext()

因此,可能会发生两个奇怪的事情:

  • 如果在迭代时删除最后一个元素,则不会抛出任何内容
    • 那是因为没有“ next”元素,所以迭代在到达修改检查代码之前就结束了
  • 如果删除倒数第二个元素,ArrayList.hasNext()实际上也会返回false,因为迭代器current index现在指向最后一个元素(以前的倒数第二个)。
    • 因此,即使在这种情况下,删除后也没有“ next”元素

请注意,所有这些都与ArrayList的文档一致:

注意,不能保证迭代器的快速失败行为,因为通常来说,在存在不同步的并发修改的情况下,不可能做出任何严格的保证。快速失败的迭代器会尽最大努力抛出ConcurrentModificationException。因此,编写依赖于此异常的程序的正确性是错误的:迭代器的快速失败行为应仅用于检测错误。



 类似资料:
  • 我正在实验/学习Spring数据neo4j。我有一个非常简单的应用程序,可以存储来自推特的推文。请参阅下面的片段。 问题是,存储哈希标签的最佳方式是什么,这样我就可以快速获取它们所属的推文?我能想到的是要么在Set上使用@索引,要么实际上创建一个单独的标签NodeEntity,并在它和推文之间建立关系。我找不到在NodeEntity中索引集合的任何留档,所以我不确定是否在set对象上创建了索引,或

  • 问题内容: 我有一个发布功能,如下所示: 现在假设在某些时候对Projects进行了更改,结果是上面返回了一个不同的项目,因此Tasks.find将返回其他任务。但是,对项目所做的更改不会重新发布 任务 我已经使用了reactPublish,但事实证明该程序包存在问题(并且也没有任何单元测试)。因此,是否有一种简单的方法可以在项目更改时重新发布此发布功能? 问题答案: 通过调用安装软件包。 添加软

  • 问题内容: 我一直遇到这个问题: 我想让hibernate管理一个表示集合集合的表。例如: 地图地图 套装清单 清单地图 例如,我希望能够代表这一点: 作为一个表: 没有自定义的hibernate代码似乎是不可能的,我不介意。但是我希望有人对自定义代码的外观有所指导。 我应该扩展AbstractPersistentCollection吗? CompositeUserType? 可以管理多个表是否正

  • 问题内容: 这里是问题:我有一个元组列表(也可以根据需要设置)。例如: 我想找到一个清单 因为一旦将所有集合放在一起,交集就不会为空。 举个例子 结果应该是 希望问题解决。那么,如果有的话,在python中最优雅的方法是什么? 干杯 问题答案: 这些是图形的 连接组件 ,可以使用诸如的图形库找到。对于第二个示例:

  • 我们从一组矩阵开始。参考集合中的所有矩阵,我想创建一个新的矩阵,它表示集合中每个矩阵的列的组合。 集合中的每个矩阵具有不同的行数。当我们组合矩阵时,新行应该用NA填充。新矩阵获取集合中每个矩阵的前3个非NA列并将它们联接起来。 设置 新矩阵: 绑定: 我希望新矩阵的行数与集合中最大的矩阵的行数相同(在本例中,nrow=11)。当集合中的矩阵行不等于11时,用NA填充它们的条目。因此,对于Mat1,