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

时间:2011-08-12 07:14:52

标签: java multithreading weblogic deadlock

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

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

这是被阻止的线程;

  

“pool-1013-thread-5”prio = 7 tid = 600000000842be00 nid = 17280   lwp_id = 518677正在等待监视器输入   [9fffffffe6aff000..9fffffffe6b00bd0] java.lang.Thread.State:   BLOCKED(在对象监视器上)at   org.apache.log4j.Category.callAppenders(Category.java:201)      - 等待锁定< 9ffffffde1e7ec88> (一个   org.apache.log4j.spi.RootLogger)at   org.apache.log4j.Category.forcedLog(Category.java:388)at   org.apache.log4j.Category.log(Category.java:853)at   org.slf4j.impl.Log4jLoggerAdapter.debug(Log4jLoggerAdapter.java:173)     在   org.hibernate.jdbc.AbstractBatcher.logOpenResults(AbstractBatcher.java:426)     在   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:   BLOCKED(在对象监视器上)at   org.apache.log4j.Category.callAppenders(Category.java:201)      - 等待锁定< 9ffffffde1e7ec88> (一个   org.apache.log4j.spi.RootLogger)at   org.apache.log4j.Category.forcedLog(Category.java:388)at   org.apache.log4j.Category.log(Category.java:853)at   org.slf4j.impl.Log4jLoggerAdapter.debug(Log4jLoggerAdapter.java:173)     在org.hibernate.loader.Loader.getRow(Loader.java:1197)at   org.hibernate.loader.Loader.getRowFromResultSet(Loader.java:603)at   org.hibernate.loader.Loader.doQuery(Loader.java:724)at   org.hibernate.loader.Loader.doQueryAndInitializeNonLazyCollections(Loader.java:259)     在org.hibernate.loader.Loader.loadEntity(Loader.java:1881)at   org.hibernate.loader.entity.AbstractEntityLoader.load(AbstractEntityLoader.java:71)     在   org.hibernate.loader.entity.AbstractEntityLoader.load(AbstractEntityLoader.java:65)     在   org.hibernate.persister.entity.AbstractEntityPersister.load(AbstractEntityPersister.java:3072)     在   org.hibernate.event.def.DefaultLoadEventListener.loadFromDatasource(DefaultLoadEventListener.java:434)     在   org.hibernate.event.def.DefaultLoadEventListener.doLoad(DefaultLoadEventListener.java:415)     在   org.hibernate.event.def.DefaultLoadEventListener.load(DefaultLoadEventListener.java:165)     在   org.hibernate.event.def.DefaultLoadEventListener.proxyOrLoad(DefaultLoadEventListener.java:223)     在   org.hibernate.event.def.DefaultLoadEventListener.onLoad(DefaultLoadEventListener.java:126)     在org.hibernate.impl.SessionImpl.fireLoad(SessionImpl.java:905)

     

“pool-1013-thread-3”prio = 7 tid = 6000000008411c00 nid = 17278   lwp_id = 518675正在等待监视器输入   [9fffffffe70ff000..9fffffffe7100ad0] java.lang.Thread.State:   BLOCKED(在对象监视器上)at   org.apache.log4j.Category.callAppenders(Category.java:201)      - 等待锁定< 9ffffffde1e7ec88> (一个   org.apache.log4j.spi.RootLogger)at   org.apache.log4j.Category.forcedLog(Category.java:388)at   org.apache.log4j.Category.log(Category.java:853)at   org.slf4j.impl.Log4jLoggerAdapter.debug(Log4jLoggerAdapter.java:173)     在   org.hibernate.jdbc.AbstractBatcher.logOpenResults(AbstractBatcher.java:426)     在   org.hibernate.jdbc.AbstractBatcher.getResultSet(AbstractBatcher.java:210)     在org.hibernate.loader.Loader.getResultSet(Loader.java:1808)at   org.hibernate.loader.Loader.doQuery(Loader.java:697)

3 个答案:

答案 0 :(得分:7)

起初我怀疑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

答案 1 :(得分:1)

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

有关

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

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

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

答案 2 :(得分:0)

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

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

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

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

有关详细信息,请参阅此处: How SocketAppender works