Relates :
|
|
Relates :
|
|
Relates :
|
|
Relates :
|
Name: nt126004 Date: 06/10/2002 FULL PRODUCT VERSION : java version "1.3.1" Java(TM) 2 Runtime Environment, Standard Edition (build 1.3.1-b24) Java HotSpot(TM) Client VM (build 1.3.1-b24, mixed mode) and java version "1.4.0" Java(TM) 2 Runtime Environment, Standard Edition (build 1.4.0-b92) Java HotSpot(TM) Client VM (build 1.4.0-b92, mixed mode) FULL OPERATING SYSTEM VERSION : Microsoft Windows 2000 [Version 5.00.2195] A DESCRIPTION OF THE PROBLEM : This problem happens both in JDK 1.3.1 and in 1.4.0, Windows 2000. When 2 threads are loading the same class with the same classloader, and somehow one of the 2 threads releases the synchronization lock on the classloader, the JVM code throws ClassCircularityError, mistakenly. Refer to the JVM class (in systemDictionary.cpp) and method SystemDictionary::resolve_instance_class_or_null(...) for where the bug is originating. Refer also to RFE #4670071. As explained there, in JBoss 3.0 (http://www.jboss.org) a new classloading model is used, not based on the tree model, that gives important features such as hot-deploy and modularity. Because of the synchronization on the classloader, JBoss' classloading model (or any other classloading mechanism not based on the tree model) may suffers of deadlocks. In JBoss 3.0 the deadlock issue has been resolved, releasing the classloader lock, but this solution showed up the ClassCircularityError bug, this time in JVM code, and hence with no solution. Probably the JVM code should throw ClassCircularityError if a placeholder is found by the same thread that put it, not if another thread is coming in asking for the same class with the same classloader. Note that the problem originates by calls that trigger a call to the native code in SystemDictionary::resolve_instance_class_or_null(...); from investigation I was able to find these methods: 1. Class.defineClass 2. Class.loadClassInternal 3. Class.newInstance (and Constructor.newInstance) 4. Class.forName There may be other, the code submitted only shows the problem with 3., but in JBoss the problem is seen it with all of the 4 cases listed above. In the code submitted, URLClassLoader has been subclassed only to make a reproducible test case, but in real code there is no need to subclass it to get the problem (only will happen only in certain situation/thread timing). It would be nice that this bug and RFE #4670071 will go on in parallell, to give more freedom to the classloading mechanism. STEPS TO FOLLOW TO REPRODUCE THE PROBLEM : 1. Make 4 files of the submitted code, namely Base.java, Derived.java, Support.java and Main.java. 2. Compile the files, for example in directory classes/ 3. java -cp classes Main EXPECTED VERSUS ACTUAL BEHAVIOR : Expected result: no errors, the 2 threads are able to load the classes Actual Result: ClassCircularityError is thrown. ERROR MESSAGES/STACK TRACES THAT OCCUR : java.lang.ClassCircularityError: Base at Support.<init>(Support.java:7) at java.lang.Class.newInstance0(Native Method) at java.lang.Class.newInstance(Class.java:237) at Main$Run1.run(Main.java:97) at java.lang.Thread.run(Thread.java:484) This bug can be reproduced always. ---------- BEGIN SOURCE ---------- public class Base {} public class Derived extends Base {} public class Support { private Base base = new Base(); } import java.net.URL; import java.net.URLClassLoader; /** * * @version $Revision$ */ public class Main { public static void main(String[] args) throws Exception { new Main(); } private Object lock = new Object(); public Main() throws Exception { URL location = getClass().getProtectionDomain().getCodeSource ().getLocation(); URLLoader loader = new URLLoader(new URL[] {location}, getClass ().getClassLoader().getParent()); Class cls = loader.loadClass("Support"); Thread t1 = new Thread(new Run1(cls)); t1.start(); Thread.sleep(1000); // Load Derived, will trigger a loadClassInternal for Base loader.loadClass("Derived"); } public class URLLoader extends URLClassLoader { private boolean m_firstTime = true; public URLLoader(URL[] urls, ClassLoader parent) { super(urls, parent); } public Class loadClass(String name) throws ClassNotFoundException { if (name.equals("Base")) { if (m_firstTime) { m_firstTime = false; // Notify the other thread synchronized (lock) { lock.notifyAll(); } // Wait on the classloader to have the JVM throw ClassCircularityError try { synchronized (this) { wait(5000); } } catch (InterruptedException ignored) { } } } return super.loadClass(name); } } public class Run1 implements Runnable { private Class cls; public Run1(Class cls) { this.cls = cls; } public void run() { synchronized (lock) { try { lock.wait(); } catch (InterruptedException ignored) {} } // Trigger loadClassInternal for Base try { cls.newInstance(); } catch (Throwable x) { x.printStackTrace(); } } } } ---------- END SOURCE ---------- CUSTOMER WORKAROUND : None, unfortunately. (Review ID: 148304) ======================================================================
|