銀行アプリケーションの負荷テスト/ベンチマークを実行しています。ConcurrentModificationException
約 100 人の仮想ユーザーで実行すると、エラーの 1 つとして発生します。以下はスタックトレースです。
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 による同時アクセスはすでに変更されてい
MODULE_SET
ます。 - 上記のため、ArrayList の実装は例外をスローします。
私の理解によると、機能を壊すことなく上記を防ぐためにコードをどのように変更する必要がありますか:
この行を変更します。
userLevelModules = new ArrayList(MODULE_SET);
このスニペットに:
LinkedHashSet moduleSetCopy = new LinkedHashSet(MODULE_SET);
// userLevelModules = new ArrayList(MODULE_SET);
userLevelModules = new ArrayList(moduleSetCopy);
だから私の質問は、
- 私の分析は正しいですか?
- コレクションの方法の 1 つを使用して同期コピーを作成する必要がありますか?それとも通常のコピーで十分ですか?
アプリケーションは、標準の Sun JDK ではなく、Oracle JRockit(R) (ビルド R28.2.5-20-152429-1.6.0_37-20120927-1915-windows-x86_64、コンパイル済みモード)を使用することに注意してください。本番レベルの環境をシミュレートする必要があるため、後者は使用しません。
更新:回答に関連するかどうかはわかりませんMODULE_SET
が、メソッドの開始時にクリアされています。