高并发多线程Java应用登录环节死锁问题排查求助
reload4j v1.2.24高并发场景下的死锁判定
问题场景
高并发多线程Java应用的登录环节出现线程阻塞,Thread-5线程卡住,使用日志库为reload4j v1.2.24,需判断是否存在死锁。
日志配置
<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/"> <appender name="default" class="org.apache.log4j.AsyncAppender"> </appender> </log4j:configuration>
线程栈分析
AsyncAppender-Dispatcher-Thread-0(调度线程)
"AsyncAppender-Dispatcher-Thread-0" #21 daemon prio=5 os_prio=0 tid=0x00007f13d2338000 nid=0x2454d waiting for monitor entry [0x00007f13a171a000] java.lang.Thread.State: BLOCKED (on object monitor) at org.apache.log4j.Category.callAppenders(Category.java:192) - waiting to lock <0x00000006c006e230> (a org.apache.log4j.spi.RootLogger) at org.apache.log4j.Category.forcedLog(Category.java:364) at org.apache.log4j.Category.log(Category.java:771) at org.slf4j.impl.Log4jLoggerAdapter.log(Log4jLoggerAdapter.java:581) at org.apache.commons.logging.impl.SLF4JLocationAwareLog.error(SLF4JLocationAwareLog.java:220)
该线程处于BLOCKED状态,正在等待获取RootLogger对象(<0x00000006c006e230>)的监视器锁,当前卡在Category.callAppenders方法中。
Thread-5(业务线程)
"Thread-5" #170 prio=5 os_prio=0 tid=0x00007f13b85d1000 nid=0x2680f in Object.wait() [0x00007f1396c20000] java.lang.Thread.State: WAITING (on object monitor) at java.lang.Object.wait(Native Method) at java.lang.Object.wait(Object.java:502) at org.apache.log4j.AsyncAppender.append(AsyncAppender.java:190) - locked <0x00000006c0026878> (a java.util.ArrayList) at org.apache.log4j.AppenderSkeleton.doAppend(AppenderSkeleton.java:228) - locked <0x00000006c007e980> (a org.apache.log4j.AsyncAppender) at org.apache.log4j.helpers.AppenderAttachableImpl.appendLoopOnAppenders(AppenderAttachableImpl.java:56) at org.apache.log4j.Category.callAppenders(Category.java:194) - locked <0x00000006c006e230> (a org.apache.log4j.spi.RootLogger) at org.apache.log4j.Category.forcedLog(Category.java:364) at org.apache.log4j.Category.log(Category.java:771) at org.slf4j.impl.Log4jLoggerAdapter.log(Log4jLoggerAdapter.java:581) at org.apache.commons.logging.impl.SLF4JLocationAwareLog.info(SLF4JLocationAwareLog.java:164)
该线程处于WAITING状态,在AsyncAppender.append方法中调用Object.wait()等待队列空间。关键是它已经持有了调度线程需要的RootLogger对象锁,同时还持有AsyncAppender和队列ArrayList的锁,但因队列满进入等待,且未释放RootLogger锁。
结论
这是典型的死锁场景:
- Thread-5持有
RootLogger锁,等待调度线程处理日志队列以唤醒自己; - 调度线程需要
RootLogger锁才能继续执行日志输出逻辑,但该锁被Thread-5持有,无法推进; - 双方陷入循环等待,且无线程能主动释放锁,形成死锁。
本质是reload4j的AsyncAppender设计缺陷:调度线程在处理日志时可能触发新的日志输出,而业务线程在写入异步日志时持有日志根节点锁,导致循环等待。
内容的提问来源于stack exchange,提问作者user24857774
相关产品推荐
相关产品推荐

