项目中日志记录是一个不可或缺的部分,通过自己定义日志信息可以保存方便我们排查问题的日志记录。然而传统的同步日志记录方式可能会在高并发环境下成为性能瓶颈。为了解决这个问题,异步日志记录成为了一种流行的优化手段。
编写一个异步日志管理器
import cn.hutool.log.Log;
import cn.hutool.log.LogFactory;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class AsyncLogger {
private static final Log log = LogFactory.get();
private static int BATCH_COMMIT_NUMBER = 200;
private static final BlockingQueue<String> QUEUE = new LinkedBlockingQueue<>(10000);
private static final List<String> UNTREATED_LIST = new ArrayList();
private static final Lock LOCK = new ReentrantLock();
private static final Condition CONDITION = LOCK.newCondition();
private AsyncLogger() {
}
static {
Thread loggerThread = new Thread(() -> {
while (!Thread.currentThread().isInterrupted()) {
try {
LOCK.lock();
if (QUEUE.isEmpty()) {
CONDITION.await();
}
while (!QUEUE.isEmpty() && UNTREATED_LIST.size() < BATCH_COMMIT_NUMBER) {
UNTREATED_LIST.add(QUEUE.take());
}
if (!UNTREATED_LIST.isEmpty()) {
log.info("达到批次数准备入库!");
//TODO 批量入库
for (String str : UNTREATED_LIST) {
log.info(str);
}
UNTREATED_LIST.clear();
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
log.error("日志消费发生异常:", e);
} finally {
LOCK.unlock();
}
}
});
loggerThread.setDaemon(true);
loggerThread.start();
}
public static void putLog(String message) {
try {
LOCK.lock();
QUEUE.put(message);
CONDITION.signalAll();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
log.error("添加日志内容发生异常:", e);
} finally {
LOCK.unlock();
}
}
}
测试一下
@GetMapping(value = "/find")
public void find() {
String orgMsg = "日志内容:";
for (int i = 1; i <= 100 ; i++) {
String msg = orgMsg + i;
AsyncLogger.putLog(msg);
}
}
结果展示