线程转储被阻止并锁定
这类似于Java线程转储:没有“等待锁定…”的BLOCKED线程 。
基本上,我看到一个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 (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 ...
而不是- locked...
另一个问题表明垃圾收集是原因,但如果是这样,那么所有线程都不会被阻塞吗? 还有其他线程是RUNNABLE。 另外,我怎么能certificate这种情况呢? 为什么这是观察到的行为? 我不想盲目地假设它是垃圾收集器只是为了发现几天之后它是别的东西。
==辅助信息==
虽然我认为它与手头的问题无关,但这是上述转储来自的代码部分。
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 (a org.apache.log4j.Logger) at org.apache.log4j.Category.forcedLog(Category.java:391) at org.apache.log4j.Category.info(Category.java:666) ...
我感兴趣的转储部分看起来不同(“锁定”而不是“等待锁定”)。 我调试了很多死锁,并查看了很multithreading转储。 我总是看到的是“等待锁定”。 我从来没有见过一个被“锁定”但仍在“等待监视器进入”的线程,我想知道这意味着什么。
这是Oracle HotSpot JVM中一个已知的化妆品错误。 如你所说,在你看到的堆栈跟踪中- locked <0x00007f3e9a0b3830>
它实际上应该说- waiting to lock <0x00007f3e9a0b3830>
因为线程尚未获得相关的锁。
有关详细信息,请参阅此错误 。
在每个Logger
上获取锁定,同时迭代其appender以防止对appender集合进行并发更改。 如果在appender中阻塞了一个线程(例如,通过网络连接写入事件),则记录到该Logger
实例的其他线程必须等待锁定。 AsyncAppender
可用于缓冲事件并最大限度地减少争用,但可能会丢失缓冲区中的事件。
奇怪的是,你不是看到“锁定” 而不是 “等待锁定”,而是除了 “锁定” 之外你没有看到“等待锁定”。 也就是说,似乎有问题的线程赢得了获取给定类别的日志的竞争,现在正在等待获取对其他对象的额外锁定。 那么,这个谜就是为什么转储不识别另一个对象?
我认为你的假设是它已经拥有锁定的Logger
是不正确的。
仍然想知道你使用的确切版本是什么?