我们正在执行银行应用程序的负载测试/基准测试。当使用大约 100 个虚拟用户运行时,我们遇到ConcurrentModificationException
了错误之一。下面是堆栈跟踪:
java.util.ConcurrentModificationException
at java.util.LinkedHashMap$LinkedHashIterator.nextEntry(LinkedHashMap.java:373)
at java.util.LinkedHashMap$KeyIterator.next(LinkedHashMap.java:384)
at java.util.AbstractCollection.toArray(AbstractCollection.java:124)
at java.util.ArrayList.<init>(ArrayList.java:131)
at my.package.AuthorizationHelper.getAuthModuleList
以下是getAuthModuleList()
导致异常的部分:
private static final LinkedHashSet MODULE_SET = new LinkedHashSet();
public static List getAuthModuleList(..)
{
MODULE_SET.clear();
....
MODULE_SET.add(getAllrequiredModules());
List userLevelModules = getAllUserLevelModules();
if (userLevelModules != null) {
MODULE_SET.addAll(userLevelModules);
}
userLevelModules = new ArrayList(MODULE_SET); //Exception here
return userLevelModules;
}
模块需要先按需要的顺序执行,因此使用LinkedHashSet
.
以下是我对 CME 原因的理解:
- 用户 A 的事务调用此方法。
- 同时,用户B也调用了这个方法。
- 当用户 A 到达异常行时,用户 B 的并发访问已经 mutated
MODULE_SET
。 - 由于上述原因,ArrayList 的实现会抛出异常。
根据我的理解,应如何修改代码以防止出现上述情况而不会破坏功能:
更改此行:
userLevelModules = new ArrayList(MODULE_SET);
到这个片段:
LinkedHashSet moduleSetCopy = new LinkedHashSet(MODULE_SET);
// userLevelModules = new ArrayList(MODULE_SET);
userLevelModules = new ArrayList(moduleSetCopy);
所以我的问题是,
- 我的分析正确吗?
- 我应该使用 Collections 方法之一制作同步副本还是普通副本就足够了?
请注意,该应用程序使用Oracle JRockit(R)(构建 R28.2.5-20-152429-1.6.0_37-20120927-1915-windows-x86_64,编译模式)而不是标准的 Sun JDK。我们需要模拟生产级环境,因此不使用后者。
更新:不确定是否与回答有关,但MODULE_SET
在方法开始时被清除。