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 ----------