代码之家  ›  专栏  ›  技术社区  ›  Dani Cricco

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

  •  13
  • Dani Cricco  · 技术社区  · 15 年前

    我正在调试一个运行多个线程的Java应用程序。看了一会儿日志后,其中一个线程似乎不再运行了。我的猜测是线程正在等待一个永远不会释放的锁(最后一个输出是在调用一个synchronized方法之前)。

    我能为线程配置一个超时吗?一种_等待这个锁,但是如果10秒后它不可用,不要再等待了!艾斯

    7 回复  |  直到 11 年前
        1
  •  24
  •   Ben Lings    15 年前

    你可以使用 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
    }
    
        2
  •  10
  •   Rich    15 年前

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

    一种选择是使用类似JConsole的东西(附带JDK),其中包括一个名为“检测死锁”的按钮(至少它在Java 6中执行,我认为它在Java 5中不起作用)。另一个选项是生成一个到控制台的线程转储-在Unix上,您可以键入kill-3,而在Windowsctrl+brk上则可以。其他的分析工具,如VisualVM(也在JDK中)可以提供帮助。终于有了 JCarder 它是“在并发多线程Java程序中寻找潜在死锁的开源工具”。

        3
  •  2
  •   Steve B.    15 年前

    可以让线程共享显式锁(参见Java.UTI.Orth.Copy.Cub)。然后您可以使用lock.trylock(),它可以接受可选的超时。

    您还可以使用Java 1.6中的JStand实用程序(不确定约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)
    
        4
  •  1
  •   skaffman    15 年前

    传统的同步方法不能使用超时。但是,使用“new”java.util.concurrent工具,可以使用支持超时的编程锁。

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

    可重入互斥锁 相同的基本行为和语义 当访问隐式监视器锁时 使用同步方法和 声明,但扩展 能力。

        5
  •  1
  •   David Nouls    15 年前

    可能有两个原因: 1)线死 2)线程被锁定在某个地方或执行了您没有预料到的操作。

    最好的解决方案是始终使用调试器(等到出现这种情况,然后将应用程序打包)或使用jconsole/jstack/jvisualvm。

        6
  •  0
  •   Il-Bhima    15 年前

    虽然在等待同步方法的锁时可能会出现超时,但是实现这些方法是不方便的。基本上,您将生成一个计时器线程,它将在T秒后中断块线程……不好。

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

        7
  •  0
  •   Sanju Thomas    11 年前

    可以使用Java管理扩展(JMX)API来确定Java中的死锁。退房 http://ourownjava.com/how-to-identify-deadlock-in-java 举个例子。