stringbuffer线程安全但性能损耗显著,因所有public方法均用synchronized锁住整个实例,导致单线程下也慢2.3倍,高并发时锁竞争加剧;仅适用于多线程共享写、低频且无法重构为线程私有场景。

StringBuffer 确实线程安全,但它的并发性能损耗不是“偶尔慢一点”,而是由设计机制决定的系统性开销。是否值得承受这份损耗,关键看实际并发模式,而非单纯线程数量。
同步锁粒度粗,无关操作也被阻塞
所有 public 方法(append、delete、toString、length 等)都用 synchronized 锁住整个对象。这意味着:
- 即使线程 A 只想在末尾 append,线程 B 只想读 length() 或访问 charAt(0),两者仍必须排队等待同一把锁
- 链式调用如
sb.append("a").append("b").append("c")会触发三次锁进出,开销叠加 - 无法按字符区间分段加锁,做不到“写后半段时前半段可被读”这类细粒度协作
单线程下也有真实开销,不止是“多线程才慢”
很多人误以为无竞争就无代价,其实 JVM 每次调用 synchronized 方法都要执行 monitor enter/exit、插入内存屏障、检查锁状态——这些指令照常运行:
- 实测 JDK 17 下,10 万次 append:StringBuilder 约 12ms,StringBuffer 约 28ms(慢 2.3 倍)
- 单线程高频拼接场景中,差距稳定在 10%–15%;若循环中反复 new 实例,同步开销仍残留约 10%
- toString() 还要维护同步保护的 toStringCache,进一步延长方法路径
扩容时双重同步放大延迟
当内部 char[] 不足,StringBuffer 扩容(新容量 = 旧容量 × 2 + 2)需两步同步:
- 先同步判断容量是否足够
- 再同步执行数组复制与替换
- 多个线程几乎同时触发扩容时,不仅争抢锁,还可能重复拷贝同一块数据,CPU 浪费在冗余复制上
真正需要 StringBuffer 的场景其实很窄
它不是过时,而是适用前提非常明确——必须同时满足:
- 多个线程共享同一个 StringBuffer 实例,且存在真实写操作竞争
- 无法重构为线程私有(如局部变量、ThreadLocal
)+ 后续合并模式 - 并发频率低(例如每分钟几次的定时配置生成),吞吐压力小
- 代码可维护性优先级高于毫秒级性能损耗
其余情况,比如 Web 请求级日志拼接、SQL 构建、JSON 组装等,用 StringBuilder 配合线程隔离更高效也更安全。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











