Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-8072592

Classloader deadlocks when Class.forName is used in a specific scenario

XMLWordPrintable

    • Icon: Bug Bug
    • Resolution: Not an Issue
    • Icon: P4 P4
    • None
    • 7u76, 8u31
    • core-libs

      FULL PRODUCT VERSION :
      Multiple versions, JDK 1.7.0_45 and 1.7.0_76 tested, also, 1.6.0_45 and

      openjdk version "1.8.0_31"
      OpenJDK Runtime Environment (build 1.8.0_31-b13)
      OpenJDK 64-Bit Server VM (build 25.31-b07, mixed mode)


      ADDITIONAL OS VERSION INFORMATION :
      Multiple attempted, Mac OSX 10.10 (Mavericks), Linux x64 CentOS

      EXTRA RELEVANT SYSTEM CONFIGURATION :
      Reproduced on a 4-core Linux VM and an 8-core MacBook Pro (2013)

      A DESCRIPTION OF THE PROBLEM :
      The situation is extremely specific. The application has 300+ running threads. A pair of ClassLoaders is used to load the relevant application classes. Thread [2] wants to load and use the class while Thread [1] is currently loading it.

      The key feature is that ClassLoader [A].findClass() delegates to [B] using Class.forName(), and then [B] delegates back to [A].findClass() for application-specific reasons. The second delegation to [A] either defines the class or throws a ClassNotFoundException. There isn't the risk of infinite recursion in this configuration.

      When [B] returns the defined class to Class.forName(), the native code there attempts to initialize the newly defined class. ClassLoader [A] is still locked, as expected, by Thread [1]. This is where the bug occurs. Before Thread [1] can initialize the class, Thread [2] somehow sneaks in and begins initialization. However, the <clinit> requires [A] to load additional classes, and the lock on [A] is held by Thread [1].

      The result is that [2] is blocking in <clinit> on [1]'s lock on [A], while [1] is stuck doing an Object.wait() in Class.forName(), waiting for [2] to finish <clinit>.

      The issue does NOT occur if [B].loadClass is invoked directly instead of using Class.forName(), or if Class.forName() is invoked with "false" for initialization.

      STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
      (1) Create ClassLoaders as described above
      (2) Create two classes to be loaded by the ClassLoaders, one of which creates a new instance of the other in its static initializer
      (3) Create 300 threads that each attempt construct a new instance of the class with an initializer

      I have demo code that locks up about 2 out of 3 times.

      EXPECTED VERSUS ACTUAL BEHAVIOR :
      EXPECTED -
      The expected result is that Class.forName() would retain the lock on ClassLoader [A] in Thread [1], perform the initialization in Thread [1], and then release the lock. Thread [2] would then proceed normally after the class has been initialized.
      ACTUAL -
      The two threads deadlocked and the classloader became unusable.

      REPRODUCIBILITY :
      This bug can be reproduced often.

            mchung Mandy Chung (Inactive)
            webbuggrp Webbug Group
            Votes:
            0 Vote for this issue
            Watchers:
            4 Start watching this issue

              Created:
              Updated:
              Resolved: