“发现1死锁”但跟踪显示未被任何线程锁定

时间:2012-06-28 07:24:42

标签: java multithreading thread-safety jvm deadlock

JVM告诉我发生了死锁:

Found one Java-level deadlock:
=============================
"TP-Processor107":
  waiting for ownable synchronizer 0x00002aaaf58e70f0, (a java.util.concurrent.locks.ReentrantReadWriteLock$NonfairSync),
  which is held by "indexTrackerThread3"
"indexTrackerThread3":
  waiting for ownable synchronizer 0x00002aaaf4394580, (a java.util.concurrent.locks.ReentrantReadWriteLock$NonfairSync),
  which is held by "TP-Processor16"
"TP-Processor16":
  waiting for ownable synchronizer 0x00002aaaf58e70f0, (a java.util.concurrent.locks.ReentrantReadWriteLock$NonfairSync),
  which is held by "indexTrackerThread3"

我们可以看到indexTrackerThread3正在等待TP-Processor16持有的资源,反之亦然。这确实是一个僵局。

我们可以看到indexTrackerThread3正在等待0x00002aaaf4394580

"indexTrackerThread3":
    - parking to wait for  <0x00002aaaf4394580>

我的问题:

the threads dump中,为什么没有行- locked <0x00002aaaf4394580>

似乎0x00002aaaf58e70f0实际上没有被任何线程锁定。什么可以锁定它?

在我阅读的所有死锁文档(example)中,对于每个不同的- parking to wait for <0x123>行,始终有一行- locked <0x123>行。所以我开始怀疑JVM错误。我误解了什么吗?

注意:很抱歉链接到pastebin,但如果没有完整转储,问题就无法解决。为简洁起见,我删除了所有包含“at”的行,它们不包含任何锁定信息。

5 个答案:

答案 0 :(得分:4)

java.util.concurrent包使用了一种特殊的本机停放机制(以及其他本机机制,例如原子比较和交换)。你可以看到我在说什么here

您描述的通常在线程转储中出现的模式源于经典的Java习语synchronized(lock) { lock.wait(); }

答案 1 :(得分:0)

Marko Topolnik的回答是正确的。

至于问题的解决方案,JProfiler会显示一个完整的线程和监视器图,用于锁定来自java.util.concurrent包的锁的情况。

免责声明:我公司开发JProfiler

答案 2 :(得分:0)

不同的东西可以死锁java线程,监视器,也就是synchronized关键字,只是一件事。

A lock can be a built-in object monitor, an ownable synchronizer, or the Condition object associated with synchronizers.

您还可以深入了解ThreadMXBean.findDeadlockedThreads和ThreadMXBean.findMonitorDeadlockedThreads的定义。

就我而言,它是监视器锁定和java 5锁定。

在线程转储中,waiting to lock <0x123>locked <0x123>组合仅用于监视器锁定。 使用java 5锁定只能获得第一部分。 像parking to wait for <0x456>这样的东西。然后在线程转储中搜索一些0x456,但无处可寻。这很令人困惑。

答案 3 :(得分:0)

此类死锁的线程转储分析的复杂性主要是由于使用了java.util.concurrent包。这是为了摆脱同步Java对象的经典和侵入式方式。例如,当您希望将WRITE操作限制为单个Thread模型同时允许并发READ操作时,此包非常有用。从性能调优的角度来看,这种方法很棒,副作用是处理并发问题时线程转储分析过程的复杂程度增加。

我建议您也查看以下文章。它描述了诸如hidden Java deadlock场景的问题,其中JVM甚至无法检测到死锁(由于READ锁通常不是为了拥有所有权的概念)。提供示例Java程序作为示例。

答案 4 :(得分:0)

堆栈跟踪显示0x00002aaaf4394580未被任何线程锁定。这可能是由Java bug #6822370引起的。这种观察应该为voted answer添加闭包。