最近、EH キャッシュを使用して Shiro を Web アプリケーションに追加しましたが、それ以降、いくつかの ConcurrentModificationException が発生しています。
[shiro-active%0053ession%0043ache.data] ERROR net.sf.ehcache.store.disk.DiskStorageFactory - Disk Write of 3ae3f634-cd97-4614-bd04-517d81623971 failed:
net.sf.ehcache.CacheException: Failed to serialize element due to ConcurrentModificationException. This is frequently the result of inappropriately sharing thread unsafe object (eg. ArrayList, HashMap, etc) between threads
at net.sf.ehcache.store.disk.DiskStorageFactory.serializeElement(DiskStorageFactory.java:401)
at net.sf.ehcache.store.disk.DiskStorageFactory.write(DiskStorageFactory.java:381)
at net.sf.ehcache.store.disk.DiskStorageFactory$DiskWriteTask.call(DiskStorageFactory.java:473)
at net.sf.ehcache.store.disk.DiskStorageFactory$PersistentDiskWriteTask.call(DiskStorageFactory.java:1067)
at net.sf.ehcache.store.disk.DiskStorageFactory$PersistentDiskWriteTask.call(DiskStorageFactory.java:1051)
at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:334)
at java.util.concurrent.FutureTask.run(FutureTask.java:166)
私が抱えている問題は、問題がコード内のどこにあるか、および webapp がかなり大きいため、スタック トレースが多くの情報を提供していないことです。
エラーを見つけて修正する方法に関するヒントをいただければ幸いです。
編集: 問題は、ユーザーが ROOT モジュール 'www.my-site.com/' からアプリ モジュール 'www.my-site.com/app/' に移動したときに発生するようです。両方のモジュールが異なるキャッシュ/セッションで Shiro を実行しています (つまり、まだ SSO はありません)。それらが共有するのは、locale/currency/cookie-consent の 3 つの Cookie だけです。リクエストの開始時にアクセスされるため、Cookie からのものではないと思います (つまり、ROOT を離れてアプリにアクセスするときは、アプリのみが Cookie にアクセスし、セッションにロケールを保存します)。
問題の原因は何ですか?
--------------- 編集 -------- より詳細なスタック トレースを次に示します。Shiro の簡単なセッションが役割を果たしているようです。
Caused by: java.util.ConcurrentModificationException
at java.util.HashMap$HashIterator.nextEntry(HashMap.java:806)
at java.util.HashMap$EntryIterator.next(HashMap.java:847)
at java.util.HashMap$EntryIterator.next(HashMap.java:845)
at java.util.HashMap.writeObject(HashMap.java:1012)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:601)
at java.io.ObjectStreamClass.invokeWriteObject(ObjectStreamClass.java:962)
at java.io.ObjectOutputStream.writeSerialData(ObjectOutputStream.java:1480)
at java.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.java:1416)
at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1174)
at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:346)
at org.apache.shiro.session.mgt.SimpleSession.writeObject(SimpleSession.java:461)
-------------編集2 ------------------
問題の原因を見つけたと思います。セッションにいくつかの文字列属性を格納するメソッドがあります。アプリはそれがなくても正常に動作し、コメントを外すとすぐに問題が再発します。私が理解していないのは、これが同時変更の例外を引き起こしている理由です。このメソッドはセッションに文字列を保存するだけで、セッションにアクセスするスレッドは 1 つだけです。手がかりはありますか?
-----------編集3 -------------------
Strings を 4 つの POJO に置き換えました。これで例外は、ユーザーが最初にページにアクセスしたとき (doGet(...) コードの実行を開始する直前) に 1 回だけ発生します。
これは動作上の問題を引き起こしているようには見えないので、今のところ無視することにします。誰かが何が起こっているのか理解できたら、私に声をかけてください。