(Является ли использование статических инициализаторов в Java хорошей идеей, выходит за рамки этого вопроса.)
Я встречаюсь с тупиками в моем приложении Scala, которое, как мне кажется, вызвано блокировкой статических инициализаторов в скомпилированных классах.
Мой вопрос заключается в том, как обнаружить и диагностировать эти взаимоблокировки. Я обнаружил, что обычные инструменты JVM для взаимоблокировок не работают, когда задействуются блоки статического инициализатора.
Вот простой пример приложения Java, который блокирует статический инициализатор:
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();
}
}
Если вы запустите это приложение, оно будет заблокировано. Трассировка стека во время тупиковой ситуации (от jstack
) содержит следующие два тупиковых потока:
"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
Мои вопросы следующие
- Почему первый поток отмечен как RUNNABLE, когда он действительно ждет блокировки? Могу ли я каким-то образом определить "реальное" состояние этого потока?
- Почему ни один поток не отмечен как владелец каких-либо (релевантных) блокировок, когда на самом деле один хранит статический блокиратор intializer, а другой ожидает его? Могу ли я каким-то образом обнаружить блокировку блокировки инициализатора?