如何检测死锁?同步块超时?

时间:2009-07-28 14:44:57

标签: java multithreading deadlock

我正在调试运行多个线程的Java应用程序。经过一段时间观察日志后,似乎其中一个线程不再运行了。我的猜测是线程正在等待一个永不释放的锁(最后一个输出是在调用同步方法之前)。

我可以为线程配置超时;一种“等待这种锁定,但如果在10秒后不能使用,则不要再等了!”

7 个答案:

答案 0 :(得分:25)

您可以使用java.util.concurrent.Lock代替内在Object锁定。没有公平排序的RentrantLock具有与内部锁相同的基本行为和语义。有一个方法tryLock采用超时参数:

Lock lock = ...;
if (lock.tryLock(10L, TimeUnit.SECONDS)) {
    try {
        // manipulate protected state
    } finally {
        lock.unlock();
    }
} else {
      // perform alternative actions
}

答案 1 :(得分:10)

您可以使用调试工具或分析器,而不是添加额外的调试代码。

一个选项是使用类似JConsole(随JDK一起提供)的东西,其中包含一个名为“Detect Deadlock”的按钮(至少它在Java 6中有用,我认为它不适用于Java 5)。另一个选择是生成一个线程转储到控制台 - 在Unix上,您可以键入“kill -3”,而在Windows上CTRL + BRK将起作用。其他分析工具(如VisualVM(也在JDK中))可以提供帮助。最后有JCarder这是“用于在并发多线程Java程序中查找潜在死锁的开源工具”。

答案 2 :(得分:2)

您可以让线程共享一个显式锁(请参阅java.util.concurrent.lock.Lock)。然后,您可以使用Lock.tryLock(),它可以执行可选的超时。

您还可以使用java 1.6附带的jstack实用程序(不确定1.5),它将打印出所有线程的状态以及它们可能或不可能等待的内容。只需使用进程ID调用它即可。例如。 :

  > jstack PID 

        "Signal Dispatcher" daemon prio=10 tid=0x00000000408e8400 nid=0x79a8 runnable [0x0000000000000000..0x000000004143f810]
           java.lang.Thread.State: RUNNABLE

        "Finalizer" daemon prio=10 tid=0x00000000408c9400 nid=0x79a7 in Object.wait() [0x0000000041a7b000..0x0000000041a7bb00]
           java.lang.Thread.State: WAITING (on object monitor)
            at java.lang.Object.wait(Native Method)
            - waiting on <0x00007f992d1e7050> (a java.lang.ref.ReferenceQueue$Lock)
            at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:116)
            - locked <0x00007f992d1e7050> (a java.lang.ref.ReferenceQueue$Lock)
            at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:132)
            at java.lang.ref.Finalizer$FinalizerThread.run(Finalizer.java:159)

        "Reference Handler" daemon prio=10 tid=0x00000000408c2000 nid=0x79a6 in Object.wait() [0x000000004197a000..0x000000004197ac80]
           java.lang.Thread.State: WAITING (on object monitor)
            at java.lang.Object.wait(Native Method)
            - waiting on <0x00007f992d41a958> (a java.lang.ref.Reference$Lock)
            at java.lang.Object.wait(Object.java:485)
            at java.lang.ref.Reference$ReferenceHandler.run(Reference.java:116)
            - locked <0x00007f992d41a958> (a java.lang.ref.Reference$Lock)

答案 3 :(得分:1)

您不能使用传统同步方法的超时。但是,使用“new”java.util.concurrent东西,你可以使用具有超时支持的程序锁。

例如,请查看java.util.concurrent.locks.ReentrantLock

  

重入互斥锁定   相同的基本行为和语义   作为隐式监视器锁访问   使用同步方法和   陈述,但有扩展   能力。

答案 4 :(得分:1)

有两个原因: 1)线程死了 2)线程被锁定在某处或做了一些你没想到的事情。

最好的解决方案是始终使用调试器(等到情况发生然后暂停应用程序)或使用JConsole / JStack / JVisualVM。

答案 5 :(得分:0)

虽然在等待同步方法的锁定时可能会有超时,但实现这些方法并不实用。基本上你会产生一个计时器线程,它会在T秒后中断块线程......不太好。

如果您使用的是Java 5或更高版本,我强烈建议您查看新的并发类提供的内容。例如,您可以考虑使用ReentrantLock,它有一个方法tryLock(long timeout, TimeUnit unit),它允许您尝试获取锁定,但允许您在一段固定的时间后逃脱。

答案 6 :(得分:0)

您可以使用Java Management Extension(JMX)API来确定java中的死锁。查看http://ourownjava.com/how-to-identify-deadlock-in-java以获取示例。