JDK-7031759 : Deadlock due to java.lang.Class.initAnnotationsIfNecessary
  • Type: Bug
  • Component: core-libs
  • Sub-Component: java.lang:reflect
  • Affected Version: 6u24
  • Priority: P4
  • Status: Closed
  • Resolution: Duplicate
  • OS: linux
  • CPU: x86
  • Submitted: 2011-03-28
  • Updated: 2012-09-28
  • Resolved: 2012-01-11
Related Reports
Duplicate :  
Description
FULL PRODUCT VERSION :
java -version                                                                                                                                                                                                                      git:master
java version "1.6.0_24"
Java(TM) SE Runtime Environment (build 1.6.0_24-b07)
Java HotSpot(TM) 64-Bit Server VM (build 19.1-b02, mixed mode)


ADDITIONAL OS VERSION INFORMATION :
Linux HOSTNAME 2.6.32-28-generic #55-Ubuntu SMP Mon Jan 10 23:42:43 UTC 2011 x86_64 GNU/Linux


EXTRA RELEVANT SYSTEM CONFIGURATION :
not relevant

A DESCRIPTION OF THE PROBLEM :
The private method initAnnotationsIfNecessary, called every time annotations are being retrieved from the Class object, is synchronized on the class instance.

Any static synchronized method in a class also synchronizes on the class instance.

This means that any static synchronized method on a class might cause deadlocks.

STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Try to retrieve annotations on a class while another thread is holding the class lock, perhaps via a static synchronized method.  See the submitted sample code.

EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
[Ljava.lang.annotation.Annotation;@<hashcode>
ACTUAL -
deadlock

REPRODUCIBILITY :
This bug can be reproduced always.

---------- BEGIN SOURCE ----------
import java.util.concurrent.*;


public class Deadlock {
    public static synchronized void main(String[] args) throws Exception {
        Callable<Object> c = new Callable<Object>() {
            @Override
            public Object call() throws Exception {
                return SyncBug.class.getAnnotations();
            }
        };
        Future<Object> future = Executors.newSingleThreadExecutor().submit(c);
        System.out.println(future.get());
    }
}

---------- END SOURCE ----------

CUSTOMER SUBMITTED WORKAROUND :
Don't ever use static synchronized methods or syncronize on the class.