Log4J blocked 問題

鏈接轉載:http://www.cnblogs.com/suxuan/p/5041420.html

"qtp1056944384-232" prio=10 tid=0x00007f54900d0800 nid=0x63b3 waiting for monitor entry [0x00007f54492d0000]
   java.lang.Thread.State: BLOCKED (on object monitor)
	at org.apache.log4j.Category.callAppenders(Category.java:205)
	- waiting to lock <0x00000007e81c4830> (a org.apache.log4j.spi.RootLogger)
	at org.apache.log4j.Category.forcedLog(Category.java:391)
	at org.apache.log4j.Category.log(Category.java:856)
	at org.slf4j.impl.Log4jLoggerAdapter.info(Log4jLoggerAdapter.java:368)

 總計有200多個log4j的線程在等待鎖"0x00000007e81c4830",而這把鎖被誰持有呢?通過搜索,找到以下dump信息:

"qtp1056944384-218" prio=10 tid=0x00007f54800bb800 nid=0x63a5 runnable [0x00007f544a0de000]
   java.lang.Thread.State: RUNNABLE
	at java.net.SocketOutputStream.socketWrite0(Native Method)
	at java.net.SocketOutputStream.socketWrite(SocketOutputStream.java:109)
	at java.net.SocketOutputStream.write(SocketOutputStream.java:141)
	at net.logstash.log4j.SocketAppender.append(SocketAppender.java:190)
	at org.apache.log4j.AppenderSkeleton.doAppend(AppenderSkeleton.java:251)
	- locked <0x00000007e8210868> (a net.logstash.log4j.SocketAppender)
	at org.apache.log4j.helpers.AppenderAttachableImpl.appendLoopOnAppenders(AppenderAttachableImpl.java:66)
	at org.apache.log4j.Category.callAppenders(Category.java:206)
	- locked <0x00000007e81c4830> (a org.apache.log4j.spi.RootLogger)
	at org.apache.log4j.Category.forcedLog(Category.java:391)
	at org.apache.log4j.Category.log(Category.java:856)
	at org.slf4j.impl.Log4jLoggerAdapter.info(Log4jLoggerAdapter.java:368)

爲什麼log4j會出現幾百個線程等待一個鎖的問題呢?log4j的Category.callAppenders源碼:

  /**
     Call the appenders in the hierrachy starting at
     <code>this</code>.  If no appenders could be found, emit a
     warning.

     <p>This method calls all the appenders inherited from the
     hierarchy circumventing any evaluation of whether to log or not
     to log the particular log request.

     @param event the event to log.  */
public void callAppenders(LoggingEvent event) {
    int writes = 0;

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

    if(writes == 0) {
      repository.emitNoAppenderWarning(this);
    }
  }

og4j版本1.x中,使用的是古老的synchronized(this),所有線程共用一個Category,而它通過log4j.properties指定。 同一個Category下的線程打log時,需要進行全局同步,因此它的效率會很低,log4j 1.x版不適合高併發的場景。

爲了杜絕這樣的問題,後續需要吸取教訓:

1. 儘量減少不必要的日誌,在成熟的接口上,關閉日誌輸出,這樣有利於提高效率。

2. 替換底層log的實現類,不再使用log4j 1.x,使用logback(推薦)或者新的log4j 2.x版本。

最後,附帶兩篇關於log4j 1.x中,日誌系統死鎖的分析(我們最開始懷疑是這個問題):

https://bz.apache.org/bugzilla/show_bug.cgi?id=50213

http://javaeesupportpatterns.blogspot.com/2012/09/log4j-thread-deadlock-case-study.html


---------------
slf4j jar sources 下載: http://www.slf4j.org/download.html
log4j jar sources 下載: http://archive.apache.org/dist/logging/log4j/2.7/
log4j2 配置:
   http://www.cnblogs.com/morvenhuang/p/3958086.html
   官方配置:http://logging.apache.org/log4j/2.x/manual/configuration.html#AutomaticConfiguration

log4j和log4j2 分別配置http://josh-persistence.iteye.com/blog/2205021

發佈了30 篇原創文章 · 獲贊 4 · 訪問量 8萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章