arrayblockingqueue 作为日志缓冲区核心,采用有界阻塞队列实现生产者-消费者解耦,支持多线程安全出入队、防内存溢出;典型三角色为采集线程(offer非阻塞)、落盘线程(take批量写磁盘)、守护线程(shutdown时drainto);需合理设容量、启用公平锁、复用日志对象并注册shutdownhook。

ArrayBlockingQueue 作为日志缓冲区的核心设计
ArrayBlockingQueue 是一个有界、线程安全的阻塞队列,底层基于 ReentrantLock + Condition 实现,适合在高并发写日志场景中做“生产者-消费者”解耦。它天然支持多线程安全入队(offer/put)和出队(poll/take),无需额外加锁,且容量固定可防内存溢出——这对日志系统至关重要:避免突发流量打爆堆内存。
典型三角色分工:日志采集、缓冲、落盘
建议拆分为三个明确角色:
- 日志采集线程(多个):业务线程调用 Logger.info() 时,仅执行 queue.offer(logEntry),非阻塞快速返回;若队列满,可丢弃低优先级日志(如 DEBUG)或降级为同步写(需配置策略)
- 单个落盘消费线程:用 while + queue.take() 持续拉取,批量写入磁盘(如每 100 条或 100ms flush 一次),减少 IO 次数
- 守护线程(可选):监听 JVM 关闭钩子,在 shutdown 时 drainTo 清空剩余日志,确保不丢失
关键配置与性能优化点
初始化时需权衡容量与响应性:
- 容量设为 2^N(如 1024、4096),避免频繁扩容(ArrayBlockingQueue 不扩容,但过大易占内存,过小易丢日志)
- 使用 new ArrayBlockingQueue(capacity, true) 启用公平锁,降低高并发下线程饥饿概率(尤其在日志峰值时)
- 落盘线程建议设置为 Thread.setDaemon(false) 并注册 ShutdownHook,防止进程退出时日志截断
- 日志对象尽量复用(如用 StringBuilder 构建 + logEntry.clear()),避免 GC 压力
简单可靠落地示例
不依赖 Logback 或 Log4j,纯 JDK 实现核心骨架:
// 初始化
private static final ArrayBlockingQueue<string> logQueue =
new ArrayBlockingQueue(8192, true);
<p>// 采集端(任意业务线程调用)
public static void asyncLog(String msg) {
if (!logQueue.offer("[INFO] " + System.currentTimeMillis() + " - " + msg)) {
// 队列满,按需处理:丢弃 / 记录告警 / 降级同步写
System.err.println("Log queue full, dropped: " + msg);
}
}</p>
<p>// 落盘线程(启动一次)
new Thread(() -> {
List<string> batch = new ArrayList(512);
try (PrintWriter writer = new PrintWriter(new FileWriter("app.log", true))) {
while (!Thread.currentThread().isInterrupted()) {
batch.clear();
// 批量拉取,兼顾实时性与吞吐
logQueue.drainTo(batch, 512);
if (!batch.isEmpty()) {
batch.forEach(writer::println);
writer.flush();
}
Thread.sleep(10); // 防忙等,也可用 take() 单条处理
}
} catch (Exception e) {
e.printStackTrace();
}
}, "log-flusher").start();
</string></p></string>Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











