JDK-6989440 : tomcat test from dacapo benchmark fails with ConcurrentModificationException
  • Type: Bug
  • Component: core-libs
  • Sub-Component: java.util:i18n
  • Affected Version: 7
  • Priority: P2
  • Status: Closed
  • Resolution: Fixed
  • OS: generic
  • CPU: generic
  • Submitted: 2010-10-04
  • Updated: 2011-09-09
  • Resolved: 2011-03-08
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
JDK 7
7 b116Fixed
Related Reports
Relates :  
Description
Tomcat test from dacapo benchmark could fail with 
java.util.ConcurrentModificationException
	java.util.ArrayList$Itr.checkForComodification(ArrayList.java:810)
	java.util.ArrayList$Itr.next(ArrayList.java:782)
	java.util.AbstractCollection.addAll(AbstractCollection.java:336)
	java.util.HashSet.<init>(HashSet.java:117)
	sun.util.LocaleServiceProviderPool.getAvailableLocales(LocaleServiceProviderPool.java:206)
	java.text.DateFormat.getAvailableLocales(DateFormat.java:575)
	org.apache.taglibs.standard.tag.common.fmt.FormatDateSupport.doEndTag(Unknown Source)
	org.apache.jsp.jsp.jsp2.jspx.basic_jspx._jspx_meth_fmt_005fformatDate_005f0(basic_jspx.java:107)
	org.apache.jsp.jsp.jsp2.jspx.basic_jspx.access$0(basic_jspx.java:94)
	org.apache.jsp.jsp.jsp2.jspx.basic_jspx$Helper.invoke0(basic_jspx.java:173)
	org.apache.jsp.jsp.jsp2.jspx.basic_jspx$Helper.invoke(basic_jspx.java:191)
	org.apache.jsp.tag.web.xhtmlbasic_tag.doTag(xhtmlbasic_tag.java:79)
	org.apache.jsp.jsp.jsp2.jspx.basic_jspx._jspx_meth_tags_005fxhtmlbasic_005f0(basic_jspx.java:89)
	org.apache.jsp.jsp.jsp2.jspx.basic_jspx._jspService(basic_jspx.java:63)
	org.apache.jasper.runtime.HttpJspBase.service(HttpJspBase.java:70)
	javax.servlet.http.HttpServlet.service(HttpServlet.java:717)
	org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:374)
	org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:342)
	org.apache.jasper.servlet.JspServlet.service(JspServlet.java:267)
	javax.servlet.http.HttpServlet.service(HttpServlet.java:717)


when running with number of threads more than 2.

Comments
EVALUATION 1. An instance of LocaleServiceProviderPool calls the method getAvailableLocales(), which calls getJRELocales() - line 206 2. Another instance of LocaleServiceProviderPool calls getJRELocales() (may or may not be the same call stack). 3. Two threads can enter getJRELocales() via two different LocaleServiceProviderPool instances - it's synchronized "instance" method. The first thread see the "static" field availableLocales is null, then entering the if block starting line 257. Before the new ArrayList written back to availableLocales at line 258, the second thread enters the method getJRELocales() and see the field availableJRELocales is still null. 4. Before the first thread reaches to "return availableJRELocales;" at line 263, the second thread update availableJRELocales with a new ArrayList. Then still in for loop at line 259. 5. The first thread returned to getAvailableLocales at line 206 and create a new HashSet from the list, while second thread is still adding locales. It looks this bug has been there, but not reproduced by the test case because getJRELocales was previously pretty lightweight (converting Locale[] to List without normalization) and less chance to encounter such situation (but logically, this could happen). There are several ways to fix this problem - 1) Change the method getJRELocales static - private synchronized List<Locale> getJRELocales() -> private static synchronized List<Locale> getJRELocales() 2) Add synchronized block in getJRELocales() private static synchronized List<Locale> getJRELocales() { synchronized (availableJRELocales) { // <- synchronize availableJRELocales field if (availableJRELocales == null) { Locale[] allLocales = LocaleData.getAvailableLocales(); availableJRELocales = new ArrayList<Locale>(allLocales.length); for (Locale locale : allLocales) { availableJRELocales.add(getLookupLocale(locale)); } } // <- end of the synchronized block } return availableJRELocales; } In this case, the method signature itself does not need to be "synchronized"
08-10-2010