我正在调试运行多个线程的Java应用程序。经过一段时间观察日志后,似乎其中一个线程不再运行了。我的猜测是线程正在等待一个永不释放的锁(最后一个输出是在调用同步方法之前)。
我可以为线程配置超时;一种“等待这种锁定,但如果在10秒后不能使用,则不要再等了!”
答案 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以获取示例。