java log4j 多线程_针对log4j 1.2.15中的并发锁问题,到底是io瓶颈,还是锁竞争导致线程block?...

先回答主要问题:到底是io瓶颈,还是锁竞争导致线程block?

死锁是显而易见的,一是因为它会一直阻塞而系统load很低,二是也很容易通过jstack监测到死锁。

另外一个问题:另外我对他文末提供的关于每个调用处static 一个Logger的做法并不能解决锁竞争的问题

static确实无法解决问题,后面的复现例子会演示这一点。

Bugzilla上的这个评论已经提出了一种死锁的场景。其实Category#callAppenders里面的同步块本身并没有大问题,甚至AppenderAttachableImpl#appendLoopOnAppenders方法里还会调用一个synchronized修饰的AppenderSkeleton#doAppend方法,但是两层加锁是有一致顺序的,不会出现死锁。

真正的问题在于,你传递给Logger#info(Object message)系列方法的这个message对象,鬼知道它的Object#toString方法是怎么实现的。

解决方案见最后,我先简单复现一下:

log4j_dead.properties

log4j.rootLogger = INFO,CONSOLE

log4j.logger.CHILD=INFO,CONSOLE

log4j.additivity.CHILD=false

log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender

log4j.appender.CONSOLE.layout=org.apache.log4j.SimpleLayout

Log4jDeadLockTest.java

package com.demo;

import org.apache.log4j.LogManager;

import org.apache.log4j.Logger;

import org.junit.Test;

/*** log4j 1.2.17*/

public class Log4jDeadLockTest {

static {

System.setProperty("log4j.configuration", "log4j_dead.properties");

}

static class Lazy {

// static的解法其实没啥用private static final Logger CHILD = Logger.getLogger("CHILD");

private static final Logger ROOT = Logger.getRootLogger();

}

@Test

public void test() {

Lazy.CHILD.info(new Object() {

@Override

public String toString() {

// 1. main线程:CHILD logger锁和CONSOLE appender锁已获得//

new Thread(new Runnable() {

@Override

public void run() {

// 2. background线程:ROOT logger锁已获得,阻塞等待CONSOLE appender锁Lazy.ROOT.info(null);

}

}, "background").start();

try {

Thread.sleep(500);

} catch (InterruptedException ignored) {

}

// 3. main线程:阻塞等待ROOT logger锁Lazy.ROOT.info(null);

return null;

}

});

}

}

有啥简单的解决方法呢?我在编写上面的demo的过程中,第一个版本习惯性用的slf4j+log4j组合,结果无法复现,然后我翻了下源码:

org.slf4j.impl.Log4jLoggerAdapter.java

public void info(String format, Object... argArray) {

if (logger.isInfoEnabled()) {

FormattingTuple ft = MessageFormatter.arrayFormat(format, argArray);

logger.log(FQCN, Level.INFO, ft.getMessage(), ft.getThrowable());

}

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值