【问题标题】:ConcurrentModificationException in HashSetHashSet 中的 ConcurrentModificationException
【发布时间】:2013-08-20 20:17:39
【问题描述】:

我的代码如下,我得到 ConcurrentModificationException,特别是在 (String file : files) 行中

我在迭代时没有对“文件”进行任何更改,那么为什么会导致异常,我应该如何避免呢?感谢您的任何建议!

int getTotalLength(final HashSet<String> files) {
        int total = 0;
        int len;
        for (String file : files) {
            len = getLength(file);
            if (len != Long.MIN_VALUE) {
                total += len;
            }
        }
        return total;
    }




      int getLength(String file) {
        int len = Long.MIN_VALUE;

        if (file == null) {
            return len;
        }

        File f = new File(file);

        if (f.exists() && f.isFile()) {
            len = f.length();
        }

        return size;
    }

【问题讨论】:

  • 那么您是否有任何其他线程可能同时修改该集合?
  • 是的,这是可能的,但我已将 hashSet 设置为最终...不会阻止集合被修改吗?
  • ConcurrentModification 在您的 HashSet 上,而不是在您的文件上
  • @GreenHo:不,你已经创建了 变量 final。这与变量值所引用的object是否可以修改无关。
  • @JonSkeet 这种混乱是我渴望在 Java 中使用 const 的很大一部分原因,更不用说它会消除对 Guava 的 Immutable* 类的需求。 :-D

标签: multithreading hashmap hashset concurrentmodification


【解决方案1】:

参考您的评论,声明 final HashSet&lt;String&gt; files 使变量 files 成为结局 - 这意味着您不能在该变量的范围内将另一个对象分配给该变量。 HashSet 本身是可变对象,可以修改 - 它与 final 修饰符无关(对 set 对象的引用 itselt 仍然相同)。 如果您想在同一个对象(同一个哈希集)上同时工作,请使用synchronized 块或方法。

一般来说,您不能修改正在使用for 循环在for-each 类似变体中迭代的集合(在同一个或另一个线程中)。

【讨论】:

  • 调用 getTotalLength() 的调用者(比如 callerA )是一个已经同步的方法,并且 callerA 没有修改集合,但是调用 callerA 的 callerB 修改了集合......代码看起来像this void callerB() { 修改 HashSet;调用者A(); } void callerA() { 在我得到异常的地方调用 getTotalLength() }
  • 我应该在调用者 B 中使用同步块,这样 void callerB() { synchronized (the HashSet) { modify the hashSet; callerA() 迭代 hashSet; } }
  • 如果方法(如您所说的“同步方法”)是同步的,这意味着如果一个线程正在执行该方法(在它的“内部”),则不允许其他线程执行该方法,直到上一次执行结束。如果您同步了两个不同的方法(方法签名中带有synchronized 关键字),它们不会相互同步。您必须将公共对象上的代码显式同步到要同步的两种方法。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-09-23
  • 2016-07-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多