推荐使用Log4j2或Logback的异步Appender:Log4j2基于LMAX Disruptor,高性能低延迟;Logback AsyncAppender轻量但吞吐略低;均需合理配置队列大小、刷盘与滚动策略,避免丢日志和阻塞。

Java 中将系统日志异步输出到文件,核心是避免主线程阻塞 I/O 操作,同时保证日志不丢失、顺序合理、线程安全。推荐使用成熟日志框架(如 Log4j2 或 Logback)的异步 Appender,而非手动实现线程池写文件——后者容易出错且难以兼顾可靠性与性能。
用 Log4j2 的 AsyncAppender 实现真正异步
Log4j2 内置高性能异步日志机制(基于 LMAX Disruptor),比简单线程池更高效、低延迟、无锁。
- 引入依赖(Maven):
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.20.0</version>
</dependency> - 配置
log4j2.xml,启用异步 Appender:
<Appenders>
<File name="FileOut" fileName="logs/app.log">
<PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %c{1} - %msg%n"/>
</File>
<Async name="AsyncFile">
<AppenderRef ref="FileOut"/>
</Async>
</Appenders>
<Loggers>
<Root level="info">
<AppenderRef ref="AsyncFile"/>
</Root>
</Loggers> - 代码中直接使用 Logger,调用即异步:
Logger logger = LogManager.getLogger();
logger.info("这行日志会异步写入文件");
用 Logback 的 AsyncAppender(基于队列+单消费者线程)
Logback 提供轻量级异步封装,适合对启动时间和内存敏感的场景,但吞吐略低于 Log4j2 的 Disruptor。
- 添加依赖:
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.4.14</version>
</dependency> - 配置
logback.xml:
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>logs/app.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>logs/app.%d{yyyy-MM-dd}.%i.log</fileNamePattern>
</rollingPolicy>
<encoder>
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder>
</appender>
<appender name="ASYNC_FILE" class="ch.qos.logback.classic.AsyncAppender">
<appender-ref ref="FILE"/>
<queueSize>256</queueSize>
<discardingThreshold>0</discardingThreshold>
<includeCallerData>false</includeCallerData>
</appender>
<root level="INFO">
<appender-ref ref="ASYNC_FILE"/>
</root> - 注意:
queueSize设太小可能丢日志(默认 256),设太大占内存;生产环境建议配合neverBlock=true避免阻塞应用线程。
不推荐的手动异步方式(仅作对比)
自己用 ExecutorService + FileWriter 异步写日志,看似可控,实则隐患多:
立即学习“Java免费学习笔记(深入)”;
- 无法保证日志顺序(多个线程并发写同一文件易乱序)
- 异常未捕获会导致日志静默丢失
- 没做缓冲和批量写入,I/O 频繁,性能反而更差
- 进程退出时未 flush 或 shutdown,最后几条日志丢失
- 文件滚动、压缩、归档需全部自行实现
关键补充:确保日志不丢失
异步日志的可靠性依赖正确配置:
-
Log4j2:设置
shutdownHookEnabled="true"(默认开启),JVM 关闭前自动刷盘 -
Logback:确保
AsyncAppender的includeCallerData="false"(减少对象创建),并启用neverBlock="true" - 所有配置中,
immediateFlush="true"(FileAppender 级)可强制每次写都刷磁盘,但显著降低性能,仅调试时开启 - 线上建议搭配按时间/大小滚动策略(如
TimeBasedRollingPolicy),避免单文件过大


















