线程转储被阻止并锁定

时间:2013-12-04 17:36:43

标签: java multithreading garbage-collection synchronized thread-dump

这类似于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...。另一个问题表明垃圾收集是原因,但如果是这样的话,不是所有线程都被阻塞了吗?还有其他线程是RUNNABLE。另外,我怎么能证明这种情况呢?为什么这是观察到的行为?我不想盲目地假设它是垃圾收集器只是为了发现几天之后它是别的东西。

==辅助信息==

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

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)
        ...

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

2 个答案:

答案 0 :(得分:3)

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

有关详细信息,请参阅this bug

答案 1 :(得分:1)

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

奇怪的是,你看不到“锁定”而不是“等待锁定”,但是你没有看到“等待锁定”另外 “锁定”。也就是说,看起来有问题的线程是赢得比赛以获取给定类别的日志的线程,现在正在等待获取对其他对象的额外锁定。那么,这个谜就是为什么转储不识别另一个对象?

我认为你假设它已经锁定的Logger是不正确的。

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