由於項目用戶量比較大,測試同事採用兩百併發進行測試,在測試查過程中,查看jvm 虛擬機發現很多日誌線程出現BLOCKED,
結果如下:
起線程BLOCKED問題。"http-saoma%2F192.168.6.162-8097-184" daemon prio=10 tid=0x00002aaab0ecc800 nid=0x2d7a waiting for monitor entry [0x0000000045fa9000] java.lang.Thread.State: BLOCKED (on object monitor) at org.apache.log4j.Category.callAppenders(Category.java:204) - waiting to lock <0x00000007800020a0> (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:304)
通過日誌結果可以看出問題是出在org.apache.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); } }
我們從上面可以看出在該方法中有個synchronized同步鎖,同步鎖就會導致線程競爭,那麼在大併發情況下將會出現性能問題,同會引
那怎樣解決這個問題呢?
我們可以使用Apache log 解決這個問題,代碼如下:
private static final Log log = LogFactory.getLog("xxx");
通過測試發現,以前org.apache.log4j.Category.callAppenders線程BLOCKED問題沒有了。大家以後遇到這個問題可以採取這個方式解決。