(Whether using static initializers in Java is a good idea is out of scope for this question.)
I am encountering deadlocks in my Scala application, which I think are caused by interlocking static initializers in the compiled classes.
My question is how to detect and diagnose these deadlocks -- I have found that the normal JVM tools for deadlocks do not seem to work when static initializer blocks are involved.
Here is a simple example Java app which deadlocks in a static initializer:
public class StaticDeadlockExample implements Runnable
{
static
{
Thread thread = new Thread(
new StaticDeadlockExample(),
"StaticDeadlockExample child thread");
thread.start();
try {
thread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public static void main(String[] args)
{
System.out.println("in main");
}
public static void sayHello()
{
System.out.println("hello from thread " + Thread.currentThread().getName());
}
@Override
public void run() {
StaticDeadlockExample.sayHello();
}
}
If you launch this app, it deadlocks. The stack trace at time of deadlock (from jstack
) contains the following two deadlocked threads:
"StaticDeadlockExample child thread" prio=6 tid=0x000000006c86a000 nid=0x4f54 in Object.wait() [0x000000006d38f000]
java.lang.Thread.State: RUNNABLE
at StaticDeadlockExample.run(StaticDeadlockExample.java:37)
at java.lang.Thread.run(Thread.java:619)
Locked ownable synchronizers:
- None
"main" prio=6 tid=0x00000000005db000 nid=0x2fbc in Object.wait() [0x000000000254e000]
java.lang.Thread.State: WAITING (on object monitor)
at java.lang.Object.wait(Native Method)
- waiting on <0x000000004a6a7870> (a java.lang.Thread)
at java.lang.Thread.join(Thread.java:1143)
- locked <0x000000004a6a7870> (a java.lang.Thread)
at java.lang.Thread.join(Thread.java:1196)
at StaticDeadlockExample.<clinit>(StaticDeadlockExample.java:17)
at java.lang.Class.forName0(Native Method)
at java.lang.Class.forName(Class.java:169)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:116)
Locked ownable synchronizers:
- None
My questions are as follows
- Why is the first thread marked as RUNNABLE, when it is in fact waiting on a lock? Can I detect the "real" state of this thread somehow?
- Why is neither thread marked as owning any (relevant) locks, when in fact one holds the static intializer lock and the other is waiting for it? Can I detect the static initializer lock ownership somehow?