繁体   English   中英

如何诊断或检测Java静态初始化程序中的死锁

[英]How to diagnose or detect deadlocks in Java static initializers

(在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

我的问题如下

  1. 为什么第一个线程标记为RUNNABLE,当它实际上在等待锁定时? 我能以某种方式检测到这个线程的“真实”状态吗?
  2. 为什么两个线程都没有标记为拥有任何(相关)锁,实际上一个持有静态初始化器锁而另一个正在等待它? 我能以某种方式检测静态初始化程序锁定所有权吗?

Scala很容易陷入陷阱。

简单的解决方法或诊断(如果你在堆栈跟踪中看到临床)是让你的对象扩展App让DelayedInit从静态初始化器中取出你的代码。

一些澄清链接:

https://issues.scala-lang.org/browse/SI-7646

Scala:对象初始化程序中的并行收集导致程序挂起

http://permalink.gmane.org/gmane.comp.lang.scala.user/72499

我用我的工具尝试了这个例子,它也无法将其检测为死锁。 在与jconsole调试器稍作挣扎并重新运行该示例几次后,我注意到初始线程被标记为RUNNABLE,因为它是可运行的,这里的问题是,由于启动的线程访问静态成员,此操作在完成静态初始化程序块之后排队(这种语义在JVM规范中并不清楚,但似乎是这种情况)。

静态初始化程序没有完成,因为在这个奇怪的例子中,连接操作强制它等待线程终止,但是我注意到这个“排队”操作不会根据JVM规范明确地或隐式地获取锁。 也许这不应该被认为是死锁本身,因为如果run方法的主体包含无限循环,情况也是如此。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM