3

这类似于Java thread dump: BLOCKED thread without "waiting to lock ..."

基本上,我看到了一个 BLOCKED 线程,但它有它正在等待的锁:

"pool-1-thread-60" prio=10 tid=0x00007fbf10017000 nid=0x210 waiting for monitor entry [0x00007fbed64e3000]
   java.lang.Thread.State: BLOCKED (on object monitor)
        at org.apache.log4j.Category.callAppenders(Category.java:204)
        - locked <0x0000000742444ad0> (a org.apache.log4j.Logger)
        at org.apache.log4j.Category.forcedLog(Category.java:391)
        at org.apache.log4j.Category.info(Category.java:666)
        ...

我希望看到- waiting to lock <0x0000000742444ad0>...而不是- locked.... 另一个问题表明垃圾收集是原因,但如果是这种情况,不是所有线程都被阻塞吗?还有其他可运行的线程。另外,我怎么证明是这样的呢?为什么这是观察到的行为?我不想盲目地假设它是垃圾收集器,但几天后才发现它是别的东西。

==辅助信息==

虽然我认为它与手头的问题无关,但这是上面转储的代码部分。

for(Category c = this; c != null; c=c.parent) {
  // Protected against simultaneous call to addAppender, removeAppender,...
  synchronized(c) { //line 204
if(c.aai != null) {
  writes += c.aai.appendLoopOnAppenders(event);
}
if(!c.additive) {
  break;
}
  }
}

显然,需要在该行上获得一个锁。然而,当一个线程在这个监视器上真正被阻塞时,线程转储中的输出看起来像(这来自同一个转储):

"pool-1-thread-44" prio=10 tid=0x00007fbef0051000 nid=0x200 waiting for monitor\
 entry [0x00007fbed74f3000]
   java.lang.Thread.State: BLOCKED (on object monitor)
        at org.apache.log4j.Category.callAppenders(Category.java:204)
        - waiting to lock <0x0000000742444ad0> (a org.apache.log4j.Logger)
        at org.apache.log4j.Category.forcedLog(Category.java:391)
        at org.apache.log4j.Category.info(Category.java:666)
        ...

我感兴趣的转储部分看起来不同(“锁定”而不是“等待锁定”)。我调试了许多死锁并查看了许多线程转储。我总是看到的是“等待锁定”。我从未见过“锁定”但仍在“等待监视器进入”的线程,我想知道这意味着什么。

4

2 回答 2

3

这是 Oracle 的 HotSpot JVM 中一个已知的装饰性错误。正如您所说,在您看到的堆栈跟踪中,- locked <0x00007f3e9a0b3830>实际上应该说- waiting to lock <0x00007f3e9a0b3830>因为线程尚未获得相关锁。

有关更多详细信息,请参阅此错误

于 2014-04-07T11:52:21.237 回答
1

Logger在遍历其 appender 时在每个上获取一个锁,以防止对 appender 集合的并发更改。如果一个线程在 appender 中被阻塞(例如,通过网络连接写入事件),则记录到该Logger实例的其他线程必须等待锁定。AnAsyncAppender可用于缓冲事件并最大限度地减少争用,但有丢失缓冲区中事件的风险。

奇怪的不是你看到的是“locked”而不是“waiting to lock”,而是除了“locked”之外,你没有看到“waiting to lock ”。也就是说,有问题的线程似乎是赢得了获取给定类别日志的竞赛的线程,现在正在等待获取其他对象的附加锁。那么,谜底是为什么转储不识别另一个对象?

我认为您认为Logger它已经持有锁的假设是不正确的。

仍然想知道您使用的确切版本是什么?

于 2013-12-04T20:27:19.763 回答