Saturday, August 8, 2009

java.util.ConcurrentModificationException during serialization of a synchronized LRUMap

As many of you might now already that LRUMap is not synchronized and is not thread-safe. If you wish to use this map from multiple threads concurrently, you must use appropriate synchronization. The simplest approach is to wrap this map using Collections.synchronizedMap(Map). But even after using this method lrumap=Collections.synchronizedMap(new LRUMap(10)) , particularly when serializing the Map if multiple threads are using it it throws the java.util.ConcurrentModificationException as shown below even though it's synchronized.

It looks like when serializing the Map attribute the map is iterated through a SequencedHashMap$OrderedIterator object to get each entry from the map and then serialize it. Even the LRUMap in this case is a synchronized Map but the iterator isn't, hence it is imperative that the user manually synchronize on the map when iterating over any of its collection views, not sure if this was missed in the serialization code of LRUMap. But if you use synchronized HashMap this problem doesn't seem to happen. Be cautious of using this LRUMap like adding to a HttpSession as an session attribute where serialization happens in a high availability cluster when session bounces between nodes and that you might run into the problem and might loose some session data. Note i was using commons-collections-2.1.jar, i didn't check if this was fixed in the latest releases.

java.util.ConcurrentModificationException
at org.apache.commons.collections.SequencedHashMap$OrderedIterator.next(Unknown Source)
at org.apache.jsp.serializemap_jsp._jspService(serializemap_jsp.java:97)
at org.apache.jasper.runtime.HttpJspBase.service(HttpJspBase.java:70)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:717)
at org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:374)
at org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:342)
at org.apache.jasper.servlet.JspServlet.service(JspServlet.java:267)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:717)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:290)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:233)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:191)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:128)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:286)
at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:845)
at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:583)
at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:447)
at java.lang.Thread.run(Thread.java:619)
Jul 31, 2009 3:16:52 PM org.apache.catalina.core.StandardWrapperValve invoke

No comments: