JDK-6329105 : (rb) ResourceBundle doesn't handle Errors encountered during loadBundle
  • Type: Bug
  • Component: core-libs
  • Sub-Component: java.util:i18n
  • Affected Version: 5.0u5
  • Priority: P3
  • Status: Resolved
  • Resolution: Fixed
  • OS: solaris_10
  • CPU: sparc
  • Submitted: 2005-09-27
  • Updated: 2014-02-27
  • Resolved: 2006-01-07
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.
Other
5.0u7 b01Fixed
Related Reports
Relates :  
Relates :  
Description
FULL PRODUCT VERSION :
sources show issue in 1.4.2 and 1.5.0 

ADDITIONAL OS VERSION INFORMATION :
JDK issue

A DESCRIPTION OF THE PROBLEM :
ResourceBundle.findBundle() has a great deal of logic to prevent duplicate loading but cacheList.wait() will wait indefinitely until the active thread responsible for loading notifies.

In the event that an exception error happens sometime after the active thread assumes responsibility for loading and before it returns and notifies all, the threads will effectively lock up if it isn't able to notify them.

It can happen and did happen to me when that thread inadvertently got an OutOfMemoryError and died a premature death. Which eventually caused every thread to hang up waiting on the resource to load.

This test fails on Java 1.4 & 1.5 but worked as expected on the current
Java 1.6.

Please find attached an example of how to induce the threads locking up.
Given the nature of the issue being related to OutOfMemory and low
memory conditions, this is a bit contrived but the root issue and
resolution is the same. 

My project originally got it while using a SimpleDateFormat but because
the application was in low memory the SoftReferences were being
frequently removed from the ResourceBundle and it increased the
likelihood. That's a difficult test case to produce and very
environmental.

The attached should exit after about 2 seconds, but because the one
thread is still waiting to be notified it fails to exit. Below you'll
see the thread dump of "Thread-0" waiting while the originally
requesting "Thread-1" has already exited never to respond that it didn't
obtain the reference.

ERROR MESSAGES/STACK TRACES THAT OCCUR :
Constructed
java.lang.OutOfMemoryError: Simulated Out Of Memory
        at ResourceBundleLockup.<init>(ResourceBundleLockup.java:22)
        at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
        at sun.reflect.NativeConstructorAccessorImpl.newInstance(
NativeConstructorAccessorImpl.java:39)
        at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingC
onstructorAccessorImpl.java:27)

REPRODUCIBILITY :
This bug can be reproduced always.

---------- BEGIN SOURCE ----------
import java.util.ListResourceBundle;
import java.util.ResourceBundle;

public class ResourceBundleLockup extends ListResourceBundle
{
  public static void main(String args[]) 
  {
    Requestor requestors[] = new Requestor[2];
	for ( int i = 0; i<requestors.length; i++ ) {
	   requestors[i] = new Requestor();
	}
	for ( int i = 0; i<requestors.length; i++ ) {
	   requestors[i].start();
	}

  }

  public ResourceBundleLockup() 
  {
	 System.out.println( "Constructed" );
	 try { Thread.sleep(1000); } catch ( Exception ex ) {}
	 throw new OutOfMemoryError( "Simulated Out Of Memory" );
  }

  public Object[][] getContents() { 
         return new Object[][] { { "OkKey", "OK" } }; }

  static class Requestor extends Thread
  {
	public void run() {
	  try {
	   ResourceBundle bundle = 
            ResourceBundle.getBundle( "ResourceBundleLockup" );
	   System.out.println( "OKAY? " + bundle.getString( "OkKey" ) );
      } catch (Throwable throwable) { 
	   throwable.printStackTrace();
	   System.err.println( "Requestor Thread: " + 
             this.getName() + " ends." );
      }		
	}
  }
}
---------- END SOURCE ----------

Comments
EVALUATION The test case works fine with 1.2.2. This is a regression bug since 1.3.0.
24-10-2005

SUGGESTED FIX Call cacheList.notifyAll() in cleanUpConstructionList(). --- ./ResourceBundle.java Tue Sep 27 15:46:45 2005 *************** *** 850,855 **** --- 850,856 ---- final Thread thisThread = Thread.currentThread(); while (entries.remove(thisThread)) { } + cacheList.notifyAll(); } }
27-09-2005

EVALUATION While I was looking into 6210996, I noticed this part of the 1.5 cache implementation. The cache control was reimplemented in Mustaing (1.6).
27-09-2005