(在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我的问题如下
发布于 2014-12-18 21:10:52
Scala很容易落入陷阱。
简单的解决方法或诊断方法(如果您在堆栈跟踪中看到了斜面)是让您的对象扩展应用程序,让DelayedInit从静态初始化器中取出代码。
一些澄清的联系:
https://issues.scala-lang.org/browse/SI-7646
http://permalink.gmane.org/gmane.comp.lang.scala.user/72499
发布于 2016-11-14 11:23:13
我已经用我的工具尝试了这个例子,但它也未能检测到这是一个死锁。在与j控制台调试器进行了一些斗争并重新运行了这个示例几次之后,我注意到初始线程被标记为runnable,因为它是可运行的,这里的问题是,由于启动的线程访问了一个静态成员,这个操作在静态初始化程序块完成后排队(然而,在JVM规范中这个语义似乎并不清楚)。
静态初始化器没有完成,因为在这个奇怪的示例中,联接操作迫使它等待线程终止,但是我注意到,这个“排队”操作不会显式地或隐式地根据JVM规范获取锁。也许这本身不应该被认为是一个死锁,因为如果run方法的主体包含一个无限循环,情况也是一样的。
https://stackoverflow.com/questions/27549671
复制相似问题