【发布时间】:2019-06-06 22:14:31
【问题描述】:
下面的静态方法append()的一个版本,有时会被多个线程同时调用:
public class CMEDemo {
private static final Logger LOG = Logger.getLogger(CMEDemo.class.getName());
private static final String[] SOME_DEMO = {"albino", "mosquito", "libido"};
private static final Set<String> SET_SOURCE = new LinkedHashSet<>(Arrays.asList(SOME_DEMO));
public static void append() {
//ConcurrentModificationException is thrown in the constructor for modifiableCopy.
LinkedHashSet<String> modifiableCopy = new LinkedHashSet<>(getBuiltInFunctions());
//Exception is not thown here, or later.
Set<String> doomed = modifiableCopy.stream()
.filter(f -> f.contains("quit")).collect(Collectors.toSet());
for (String found : doomed) {
LOG.log(Level.INFO, found);
}
}
public static Set<String> getBuiltInFunctions() {
return Collections.unmodifiableSet(SET_SOURCE);
}
}
通常,一切都按预期工作,但 有时 LinkedHashSet 构造函数会抛出 ConcurrentModificationException:
java.util.ConcurrentModificationException
at java.util.LinkedHashMap$LinkedHashIterator.nextNode(LinkedHashMap.java:719)
at java.util.LinkedHashMap$LinkedKeyIterator.next(LinkedHashMap.java:742)
at java.util.Collections$UnmodifiableCollection$1.next(Collections.java:1042)
at java.util.AbstractCollection.addAll(AbstractCollection.java:343)
at java.util.LinkedHashSet.<init>(LinkedHashSet.java:169)
我的 JVM 是 Java 1.8_212。如果我设置一个测试用例来生成多个线程并让它运行一段时间,append() 最终会抛出 ConcurrentModificationException。为什么会抛出这个异常,如何安全地获取 LinkedHashSet?
【问题讨论】:
-
是否有任何代码修改
SET_SOURCE(即直接访问它,而不是通过getBuiltInFunctions())? -
是的,这就是我制作副本的原因。
-
unmodifiableSet不会复制。它返回一个 Set,它的修改方法抛出 UnsupportedOperationException,而它的其他方法委托给底层集合。如果该基础集发生更改,则unmodifiableSet将反映这些更改 - 如果您正在对其进行迭代,则会导致此异常。 -
只是为了确保,您知道
Collections.unmodifiableSet(..)不会复制传递的集合,对吧? -
不,我不认为这是副本。嗯,这可能解释了它。
标签: java linkedhashmap