直接换用StringBuffer不能自动解决高并发安全问题,关键在于是否真需共享同一实例;多数场景应继续用StringBuilder,仅当多线程共用同一对象时才考虑StringBuffer,并注意其复合操作非原子性及性能代价。

直接换用 StringBuffer 并不能自动解决高并发下的安全问题,关键不是“切换类”,而是确认是否真需要共享同一个实例。多数所谓“高并发场景”其实并不需要 StringBuffer,盲目替换反而拖慢性能。
先判断要不要共享 StringBuffer 实例
多线程环境下,只有当多个线程**同时读写同一个 StringBuffer 对象**时,才必须用它。如果每个线程都 new 自己的 StringBuilder,根本无需切换。
- 方法内局部变量:new StringBuilder() → 绝对安全,继续用 StringBuilder
- 线程池任务中每次新建:仍属独占,StringBuilder 更合适
- 静态字段或类成员变量被多线程共用:这才是 StringBuffer 的适用边界
真要共享时,StringBuffer 也有使用陷阱
StringBuffer 虽然单个 append() 是线程安全的,但连续调用不保证原子性。比如下面代码依然可能出错:
错误写法:if (buf.length() == 0) buf.append("default");
立即学习“Java免费学习笔记(深入)”;
因为 length() 和 append() 是两个独立同步方法,中间可能被其他线程插入操作。
正确做法:用 synchronized 块包裹复合逻辑
synchronized (buf) { if (buf.length() == 0) buf.append("default"); }
比 StringBuffer 更轻量的线程安全方案
如果目标只是拼接后汇总,没必要让所有线程争抢一把锁:
- 各线程用 StringBuilder 独立构建,最后用 String.join() 或 Collectors.joining() 合并
- 用 ThreadLocal
为每个线程分配专属实例,零锁开销 - 纯拼接场景可考虑 StringJoiner(JDK 8+),它无状态、不可变,天然适合并发收集
性能代价必须心里有数
实测 4 线程并发追加 10 万次,StringBuffer 耗时约为单线程 StringBuilder 的 2.8 倍。锁竞争越激烈,吞吐量下降越明显。不是“能用就行”,而是“值得用吗?”
如果只是日志聚合、配置拼装等低频写入,StringBuffer 可靠;如果是毫秒级高频拼接(如实时消息组装),应优先重构为无共享设计。


















