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

JVM Can Deadlock on Static Class Initialization

    XMLWordPrintable

Details

    • Bug
    • Status: Closed
    • P4
    • Resolution: Not an Issue
    • 7u25
    • 9
    • hotspot
    • x86
    • linux

    Description

      FULL PRODUCT VERSION :
      on Linux:
      java version "1.7.0_25"
      Java(TM) SE Runtime Environment (build 1.7.0_25-b15)
      Java HotSpot(TM) 64-Bit Server VM (build 23.25-b01, mixed mode)

      on OSX:
      java version "1.6.0_37"
      Java(TM) SE Runtime Environment (build 1.6.0_37-b06-434)
      Java HotSpot(TM) 64-Bit Server VM (build 20.12-b01-434, mixed mode)


      FULL OS VERSION :
      OSX, Linux

      A DESCRIPTION OF THE PROBLEM :
      If you define a class with a static field that depends on a subclass of that class, there is an opportunity for deadlock when multiple threads try to load the class and its subclass.

      A reproducible test case is included.

      A search of the bug database gave two results, both somewhat old and closed as won't fix:

      http://bugs.java.com/bugdatabase/view_bug.do?bug_id=4891511
      http://bugs.java.com/bugdatabase/view_bug.do?bug_id=4295661

      THE PROBLEM WAS REPRODUCIBLE WITH -Xint FLAG: Did not try

      THE PROBLEM WAS REPRODUCIBLE WITH -server FLAG: Did not try

      STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
      $ javac ClassDeadlockTest.java
      $ java ClassDeadlockTest 500

      JVM will deadlock with a thread in ClassDeadlockTest.Super.<clinit>
      while main thread is waiting to load ClassDeadlockTest.Sub




      EXPECTED VERSUS ACTUAL BEHAVIOR :
      Expected: Program will terminate
      Actual: Program deadlocks and hangs
      ERROR MESSAGES/STACK TRACES THAT OCCUR :
      Thread dump:

      Full thread dump Java HotSpot(TM) 64-Bit Server VM (23.25-b01 mixed mode):

      "Thread-0" prio=10 tid=0x00007f624410d800 nid=0x72c5 in Object.wait() [0x00007f623131e000]
         java.lang.Thread.State: RUNNABLE
      at ClassDeadlockTest$Super.getHelloString(ClassDeadlockTest.java:43)
      at ClassDeadlockTest$Super.<clinit>(ClassDeadlockTest.java:32)
      at ClassDeadlockTest$1.run(ClassDeadlockTest.java:16)

      "Service Thread" daemon prio=10 tid=0x00007f62440f0800 nid=0x72c3 runnable [0x0000000000000000]
         java.lang.Thread.State: RUNNABLE

      "C2 CompilerThread1" daemon prio=10 tid=0x00007f62440ee000 nid=0x72c2 waiting on condition [0x0000000000000000]
         java.lang.Thread.State: RUNNABLE

      "C2 CompilerThread0" daemon prio=10 tid=0x00007f62440eb000 nid=0x72c1 waiting on condition [0x0000000000000000]
         java.lang.Thread.State: RUNNABLE

      "Signal Dispatcher" daemon prio=10 tid=0x00007f62440e9000 nid=0x72c0 waiting on condition [0x0000000000000000]
         java.lang.Thread.State: RUNNABLE

      "Finalizer" daemon prio=10 tid=0x00007f624409a800 nid=0x72bf in Object.wait() [0x00007f6231924000]
         java.lang.Thread.State: WAITING (on object monitor)
      at java.lang.Object.wait(Native Method)
      - waiting on <0x00000007cc765798> (a java.lang.ref.ReferenceQueue$Lock)
      at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:135)
      - locked <0x00000007cc765798> (a java.lang.ref.ReferenceQueue$Lock)
      at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:151)
      at java.lang.ref.Finalizer$FinalizerThread.run(Finalizer.java:189)

      "Reference Handler" daemon prio=10 tid=0x00007f6244098000 nid=0x72be in Object.wait() [0x00007f62401a7000]
         java.lang.Thread.State: WAITING (on object monitor)
      at java.lang.Object.wait(Native Method)
      - waiting on <0x00000007cc765320> (a java.lang.ref.Reference$Lock)
      at java.lang.Object.wait(Object.java:503)
      at java.lang.ref.Reference$ReferenceHandler.run(Reference.java:133)
      - locked <0x00000007cc765320> (a java.lang.ref.Reference$Lock)

      "main" prio=10 tid=0x00007f6244007800 nid=0x72b8 in Object.wait() [0x00007f6248902000]
         java.lang.Thread.State: RUNNABLE
      at ClassDeadlockTest.main(ClassDeadlockTest.java:27)

      "VM Thread" prio=10 tid=0x00007f6244090800 nid=0x72bd runnable

      "GC task thread#0 (ParallelGC)" prio=10 tid=0x00007f6244015000 nid=0x72b9 runnable

      "GC task thread#1 (ParallelGC)" prio=10 tid=0x00007f6244017000 nid=0x72ba runnable

      "GC task thread#2 (ParallelGC)" prio=10 tid=0x00007f6244018800 nid=0x72bb runnable

      "GC task thread#3 (ParallelGC)" prio=10 tid=0x00007f624401a800 nid=0x72bc runnable

      "VM Periodic Task Thread" prio=10 tid=0x00007f62440fb000 nid=0x72c4 waiting on condition

      JNI global references: 110

      Heap
       PSYoungGen total 46144K, used 1582K [0x00000007cc760000, 0x00000007cfae0000, 0x0000000800000000)
        eden space 39552K, 4% used [0x00000007cc760000,0x00000007cc8eb8d8,0x00000007cee00000)
        from space 6592K, 0% used [0x00000007cf470000,0x00000007cf470000,0x00000007cfae0000)
        to space 6592K, 0% used [0x00000007cee00000,0x00000007cee00000,0x00000007cf470000)
       ParOldGen total 105600K, used 0K [0x0000000765600000, 0x000000076bd20000, 0x00000007cc760000)
        object space 105600K, 0% used [0x0000000765600000,0x0000000765600000,0x000000076bd20000)
       PSPermGen total 21248K, used 2471K [0x0000000760400000, 0x00000007618c0000, 0x0000000765600000)
        object space 21248K, 11% used [0x0000000760400000,0x0000000760669d30,0x00000007618c0000)


      REPRODUCIBILITY :
      This bug can be reproduced always.

      ---------- BEGIN SOURCE ----------
      /**
       * @author Curtis Caravone
       */
      public class ClassDeadlockTest {

          public static void main(String[] args) {
              if (args.length != 1) {
                  throw new RuntimeException("Usage: ClassDeadlockTest delay_millis (try 500 and 1500)");
              }
              int delayMillis = Integer.valueOf(args[0]);
              System.out.println("Delay = " + delayMillis + " millis");

              new Thread() {
                  @Override
                  public void run() {
                      System.out.println(Thread.currentThread() + "Created super: " + new Super());
                  }
              }.start();

              try {
                  Thread.sleep(delayMillis);
              } catch (InterruptedException e) {
                  throw new RuntimeException(e);
              }

              System.out.println(Thread.currentThread() + "Creating sub...");
              System.out.println(Thread.currentThread() + "Created sub: " + new Sub());
          }

          public static class Super {

              public static final String hello = getHelloString();

              private static String getHelloString() {
                  int sleepTime = 1000;
                  System.out.println(Thread.currentThread() + "Sleeping in Super static init for " + sleepTime + " millis");
                  try {
                      Thread.sleep(sleepTime);
                  } catch (InterruptedException e) {
                      throw new RuntimeException(e);
                  }
                  System.out.println(Thread.currentThread() + "Creating new Sub()");
                  return "Sub Instance = " + new Sub();
              }
          }

          public static class Sub extends Super {
              public Sub() {
                  System.out.println(Thread.currentThread() + "In Sub constructor");
              }
          }

      }
      ---------- END SOURCE ----------

      CUSTOMER SUBMITTED WORKAROUND :
      Rewrite class definition so that static initializers don't reference subclasses.

      Attachments

        Activity

          People

            Unassigned Unassigned
            webbuggrp Webbug Group
            Votes:
            0 Vote for this issue
            Watchers:
            3 Start watching this issue

            Dates

              Created:
              Updated:
              Resolved: