You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Log4J2 2.14.1版本Async异步追加器导致Java进程执行后挂起无法关闭

结论

该现象是Log4j2 2.10.0及以上版本的预期默认行为,不是版本BUG,也不存在配置遗漏,是版本默认规则调整导致的。

根因说明

  1. 从2.10.0版本开始,AsyncAppender的事件调度线程默认设置为非守护线程:JVM会等待所有非守护线程终止后才会退出,你线程栈里看到的WAITING状态的Log4j2-AsyncAppenderEventDispatcher线程就是非守护线程,会一直等待队列新事件,没有被主动终止的情况下会一直运行,导致进程挂起。
  2. 你没有触发Log4j2上下文的关闭流程:你之前配置的shutdownTimeout参数只有在上下文关闭流程触发时才会生效,未触发关闭的情况下该参数不会生效,所以你加这个配置没有效果。
  3. 2.9.1等低版本不存在该问题的原因是:低版本AsyncAppender的调度线程默认是守护线程,且默认开启JVM关闭钩子,main方法执行完成后要么JVM直接终止守护线程,要么关闭钩子触发主动停止异步线程,不会出现挂起问题。

解决方案

根据你的使用场景选择以下任意一种方案即可:

方案1:显式关闭Log4j2上下文(生产环境首选,无日志丢失风险)

在业务逻辑执行完成后主动关闭LoggerContext,修改后的测试代码如下:

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.core.LoggerContext;

public class TestLog {
    private static final org.apache.logging.log4j.Logger l = LogManager.getLogger(TestLog.class);
    public static void main(String[] args) {
        l.error("Boo");
        // 主动关闭日志上下文
        LoggerContext context = (LoggerContext) LogManager.getContext(false);
        context.stop();
    }
}

方案2:配置AsyncAppender使用守护线程(适合测试/日志可靠性要求低的场景)

修改log4j2.xml的Async标签,增加daemon="true"属性,调度线程会变成守护线程,main线程结束后JVM会直接退出:

<Async name="Async" daemon="true">
    <AppenderRef ref="MyFile"/>
</Async>

注意:该方案可能丢失还未刷入磁盘的队列日志,生产环境不推荐使用

方案3:开启Log4j2自动关闭钩子(无需修改业务代码,无日志丢失风险)

修改log4j2.xml的Configuration标签,增加shutdownHook="enable"属性,Log4j2会自动注册JVM关闭钩子,在JVM退出前主动停止所有异步线程、刷完所有待处理日志:

<Configuration status="warn" name="MyApp" packages="" shutdownHook="enable">
    <!-- 其余配置保持不变 -->
</Configuration>

内容的提问来源于stack exchange,提问作者Janaka Bandara

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.25 18:36:04