StringBuffer可用于多线程日志记录因其关键方法均加synchronized,天然线程安全;但因粗粒度锁导致高并发性能瓶颈,且缺乏日志框架必备功能,故推荐使用Log4j2等成熟框架或ThreadLocal优化。

StringBuffer 可以安全用于多线程日志记录,因为它内部方法都加了 synchronized,天然线程安全;但实际项目中更推荐用其他方式替代,原因在于性能开销和现代日志框架的成熟支持。
为什么 StringBuffer 能用于多线程日志场景
StringBuffer 的 append、toString 等关键方法都是同步的,多个线程同时调用不会导致数据错乱或抛出 ConcurrentModificationException。比如多个线程共用一个 StringBuffer 实例拼接日志内容,不会出现字符串截断或字符乱序。
- 所有公共修改方法(如 append、insert、delete)都用 synchronized 修饰
- 无需额外加锁,适合简单共享缓冲场景
- 比 StringBuilder 更适合在未引入日志框架的轻量级多线程程序中临时使用
但不建议直接用 StringBuffer 做日志核心载体
虽然线程安全,但同步粒度粗(整个对象锁),高并发下容易成为瓶颈。例如 10 个线程频繁调用 append,会排队等待同一把锁,吞吐量明显下降。
- 每次 append 都竞争同一把锁,无法并行执行
- 日志内容通常需格式化、时间戳、线程名等,StringBuffer 本身不提供这些能力
- 缺乏异步写入、滚动策略、级别控制等生产级日志必需功能
更合理的替代方案
优先使用成熟日志框架,它们内部已优化线程安全与性能平衡。若必须手写简易日志器,可结合局部变量 + StringBuffer 提升效率。
立即学习“Java免费学习笔记(深入)”;
- Log4j2 / SLF4J + Logback:支持异步 Appender、无锁队列、按级别过滤,线程安全且高性能
- 每个线程用独立 StringBuilder 拼接,再统一交给日志框架输出——避免锁竞争
- 如需共享缓冲,可用 ThreadLocal<StringBuffer>,每个线程持有一个实例,既免锁又复用对象
一个轻量级示例(仅作理解,非推荐上线)
以下代码演示如何用 StringBuffer 在多线程中收集日志,但仅适用于调试或极低并发场景:
private static final StringBuffer logBuffer = new StringBuffer();
public static void log(String msg) {
logBuffer.append(Thread.currentThread().getName())
.append(" [").append(System.currentTimeMillis()).append("] ")
.append(msg).append("\n");
}
// 多线程调用后,最终 dump 到文件
public static String getAndClearLogs() {
synchronized (logBuffer) {
String result = logBuffer.toString();
logBuffer.setLength(0); // 清空而非新建,减少 GC
return result;
}
}
注意:这个例子仍存在单点锁瓶颈,且没处理日志落盘、编码、异常等情况,不可直接用于生产环境。


















