“Found 1 deadlock”但跟踪显示未被任何线程锁定。

6
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>
我的问题:

线程转储中,为什么没有- locked <0x00002aaaf4394580>这一行?

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

在我读过的所有死锁文档(示例)中,对于每个不同的- parking to wait for <0x123>行,总会有一个- locked <0x123>行。所以我开始怀疑是否出现了JVM bug。我是否理解错了什么?

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

5个回答

5

Java.util.concurrent包利用一种外语本地停车机制(以及其他本地机制,例如原子比较和交换)。您可以在此处看到我所说的内容。

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


谢谢提供链接!我现在已经熟悉了Unsafe类。即使是通过调用Unsafe.park完成的,锁定仍然来自Java调用,那么为什么“locked <0x123>”部分不会在该行中编写呢?我希望能够获得任何关于id不存在的特定问题的文档资料。 - Nicolas Raoul

0

堆栈跟踪显示0x00002aaaf4394580未被任何线程锁定。这可能是由于Java bug #6822370引起的。这个观察结果应该为voted answer提供了解决方案。


0

针对这种死锁类型的线程转储分析的复杂性主要归因于java.util.concurrent包的使用。该包是为了摆脱同步Java对象的经典和侵入式方式而构建的。例如,当您想将WRITE操作限制为单个线程模型,同时允许并发READ操作时,该包非常有用。从性能调整的角度来看,这种方法非常好,但副作用是在处理并发问题时,线程转储分析过程的复杂级别会增加。

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


0

不同的事物可以导致Java线程死锁,监视器(即synchronized关键字)只是其中之一。

锁可以是内置对象监视器、可拥有同步器或与同步器相关联的条件对象。

您还可以深入了解ThreadMXBean.findDeadlockedThreads和ThreadMXBean.findMonitorDeadlockedThreads的定义,以获取更多信息。

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

在线程转储中,“等待锁<0x123>”和“已锁定<0x123>”组合仅适用于监视器锁定。使用Java 5锁定只获得第一部分,例如“停放以等待<0x456>”。然后您在线程转储中搜索一些0x456,但找不到它。这是令人困惑的。


0

Marko Topolnik的回答是正确的。

至于解决您的问题,JProfiler将为您显示涉及java.util.concurrent包锁定情况的线程和监视器的完整图形。

免责声明:我的公司开发了JProfiler


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接