怎么可能,3个线程处于阻塞状态,等待同一个监视器,并且没有线程拥有该监视器

在我们的生产环境中,weblogic服务器挂起半小时,看起来它有死锁线程。 但是在调查线程转储之后,同一个锁阻塞了3个线程,但没有其他线程拥有这个锁..这是堆栈跟踪 ..

你对这种侮辱有什么合理的解释吗?

这是被阻止的线程;

“pool-1013-thread-5”prio = 7 tid = 600000000842be00 nid = 17280 lwp_id = 518677正在等待监视器条目[9fffffffe6aff000..9fffffffe6b00bd0] java.lang.Thread.State:在org.apache上的BLOCKED(在对象监视器上)。 log4j.Category.callAppenders(Category.java:201) – 等待在org.apache.log4j.Category.forcedLog(Category.java:388)的org上锁定(一个org.apache.log4j.spi.RootLogger)位于org.hibernate.jdbc.AbstractBatcher.logOpenResults(AbstractBatcher.java:426)的org.slf4j.impl.Log4jLoggerAdapter.debug(Log4jLoggerAdapter.java:173)中的.apache.log4j.Category.log(Category.java:853) Org.hibernate.jdbc.AbstractBatcher.getResultSet(AbstractBatcher.java:210)org.hibernate.loader.Loader.getResultSet(Loader.java:1808)

“pool-1013-thread-4”prio = 7 tid = 6000000008413400 nid = 17279 lwp_id = 518676等待监视器条目[9fffffffe6eff000..9fffffffe6f00b50] java.lang.Thread.State:在org.apache上的BLOCKED(在对象监视器上)。 log4j.Category.callAppenders(Category.java:201) – 等待在org.apache.log4j.Category.forcedLog(Category.java:388)的org上锁定(一个org.apache.log4j.spi.RootLogger)位于org.hibernate.loader.Loader.getRow(Loader.java:1197)的org.slf4j.impl.Log4jLoggerAdapter.debug(Log4jLoggerAdapter.java:173)的.apache.log4j.Category.log(Category.java:853) Org.hibernate.loader.Loader.ndQuery对象(Loader.java:603)位于org.hibernate.loader.Loader.doQuery.doQuery.doQuery.doQuery.doQuery.doQueryAndInitializeNonLazyCollections(Loader.java:259)org.hibernate.loader.Loader.doQuery(Loader.java:724)中的org.hibernate.loader.Loader.getRowFromResultSet org.hibernate.loader.Loader.loadEntity(Loader.java:1881)org.hibernate.loader.entity.AbstractEntityLoader.load(AbstractEntityLoader.java:71)org.hibernate.loader.entity.AbstractEntityLoader.load(AbstractEntityLoader) .jav a:65)atg.hibernate.persister.entity.AbstractEntityPersister.load(AbstractEntityPersister.java:3072)org.hibernate.event.def上的org.hibernate.event.def.DefaultLoadEventListener.loadFromDatasource(DefaultLoadEventListener.java:434) org.hibernate.event.def.DefaultLoadEventListener.load(DefaultLoadEventListener.java:165)中的.DefaultLoadEventListener.doLoad(DefaultLoadEventListener.java:415)位于org.hibernate.event.def.DefaultLoadEventListener.proxyOrLoad(DefaultLoadEventListener.java:223)at at org.hibernate.event.If.Conmpl上的org.hibernate.event.def.DefaultLoadEventListener.onLoad(DefaultLoadEventListener.java:126)(SessionImpl.java:905)

“pool-1013-thread-3”prio = 7 tid = 6000000008411c00 nid = 17278 lwp_id = 518675正在等待监视器条目[9fffffffe70ff000..9fffffffe7100ad0] java.lang.Thread.State:在org.apache上的BLOCKED(在对象监视器上)。 log4j.Category.callAppenders(Category.java:201) – 等待在org.apache.log4j.Category.forcedLog(Category.java:388)的org上锁定(一个org.apache.log4j.spi.RootLogger)位于org.hibernate.jdbc.AbstractBatcher.logOpenResults(AbstractBatcher.java:426)的org.slf4j.impl.Log4jLoggerAdapter.debug(Log4jLoggerAdapter.java:173)中的.apache.log4j.Category.log(Category.java:853) / or.::::: or or or or or or or or or or or or or or

起初我怀疑Lock对象最终没有被解锁。 但后来我看了你提供的两个线程转储。

实际上3个线程在同一个锁上被阻塞,即它是Log4J, Category类。 根据线程转储,这是他们都被阻止的代码:

 for(Category c = this; c != null; c=c.parent) { synchronized(c) { // LOCKED HERE if(c.aai != null) { writes += c.aai.appendLoopOnAppenders(event); } if(!c.additive) { break; } } } 

TDA确认没有其他线程有此锁,但也提供了非常有用的提示:

此监视器没有锁定它的线程。 这意味着VM Thread正在持有它。 如果您看到许多监视器没有锁定线程,这通常意味着垃圾收集器正在运行。 在这种情况下,您应该考虑分析垃圾收集器输出。 如果转储有许多没有锁定线程的监视器,则单击转储节点将为您提供其他信息。

并进一步:

此线程转储包含没有锁定线程信息的监视器。 这意味着,监视器由系统线程或某些外部资源保持。 您应该检查监视器而不锁定线程以获取更多信息。

结论 :您应该启用垃圾收集日志记录,并查看这是否不是根本原因。 还要检查你或某些库是不是用Log4J(圆形类别?)做了一些奇怪的事情 – 只是一个疯狂的猜测。 有用的选择:

 -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -XX:+PrintHeapAtGC -Xloggc:gc.log 

我遇到了一个非常类似的问题。 我相信这与https://issues.apache.org/bugzilla/show_bug.cgi?id=50614有关

在你的情况下,我建议使用jstack -l,然后解析堆栈中的实际锁定对象(它们的地址与监视器地址不同) – 所以对于每个“等待锁定X”,你应该能够找到“ – 锁定X“在某个线程的堆栈中(使用jstack -l打印时)。

在我的情况下,我发现罪魁祸首线程(持有锁)实际上在Console appender的写入刷新时被阻止(并且即使堆栈跟踪表明它处于可运行状态,仍然如此)。 我也找不到死锁循环。

因此,至少有一种解决此问题的方法是在操作系统内部进行内部锁定 – 通过控制台写入刷新来触发。 因此,一个简单的解决方法是消除控制台日志追加器(或增加其级别)。

当我使用log4j SocketAppender将套接字写入logstash时,这就是我。

SocketAppender正在阻塞,当有一个事件发送到另一侧的logstash并且logstash无法处理它时(即在弹性搜索调用上阻塞),那么你的应用程序将阻止。

尝试使用该appender进行日志记录的任何其他线程将只是坐下并等待粘贴在线程转储中的阻塞状态。

解决此问题的最佳方法是使用异步appender。

有关更多信息,请参阅此处: SocketAppender的工作原理