下面的静态方法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?
答案 0 :(得分:0)
其他代码正在修改Set
包装而不是复制的SET_SOURCE
Collections.unmodifiableSet(..)
,并且在LinkedHashSet
中构造副本期间导致间歇性异常。
所以我将getBuiltInFunctions()
替换为
public static Set<String> getBuiltInFunctions() {
synchronized (SET_SOURCE) {
return Collections.unmodifiableSet(new HashSet<>(SET_SOURCE));
}
}
private static Set<String> getFunctionsRW() {
synchronized (SET_SOURCE ) {
return SET_SOURCE;
}
}