stringbuffer 性能低于 stringbuilder 的根本原因是其所有 public 方法均被 synchronized 修饰,导致每次调用都强制执行 monitor enter/exit、内存屏障及锁状态检查,无法被 jit 完全优化,实测耗时高 40%–85%,并发吞吐在多线程下迅速饱和。

StringBuffer 的方法同步开销不是“偶尔慢一点”,而是从 JVM 指令层就嵌入了确定性成本,直接影响执行路径、CPU 利用率和并发吞吐。
每次调用都走完整锁流程
哪怕单线程运行,synchronized 方法仍强制执行 monitor enter/exit 指令,触发内存屏障、锁状态检查(偏向锁尝试、轻量级锁膨胀判断等),这些操作无法被 JIT 完全消除。实测显示:100 万次 append,在 JDK 17 下 StringBuffer 耗时约 120–185ms,StringBuilder 仅需 65–112ms,差距达 40%–85%。
- 锁检查不因线程数少而跳过,JVM 必须保障语义一致性
- toString() 方法也同步,且要维护 toStringCache 字段,每次调用都增加同步路径复杂度
- 链式调用如 sb.append("a").append("b").append("c") 触发三次独立锁进出,开销叠加
粗粒度锁阻塞无关操作
所有 public 方法(包括 length()、charAt()、toString())都锁住整个 this 实例,导致本可并行的读写操作被迫串行。
- 一个线程在 append 末尾字符,另一个线程想读 length(),也得等待
- 扩容时先检查容量、再复制数组,两个步骤均被同步保护,高并发下易重复拷贝
- 无法按字符区间分段加锁,哪怕两个线程操作完全不重叠的位置,依然排队
高并发下暴露吞吐瓶颈
当线程数超过 CPU 核心数或竞争加剧,锁争抢迅速成为系统瓶颈。
- 4 线程并发 append 时,StringBuffer 吞吐增长已明显放缓;8 线程下基本停滞
- CPU 时间大量消耗在上下文切换与自旋等待,而非实际字符串拼接
- 相比 StringBuilder,低竞争多线程场景下性能差距可达 5 倍
底层共享但同步代价不可省略
StringBuffer 和 StringBuilder 共用 AbstractStringBuilder 底层实现,差异仅在于是否加 synchronized——这意味着所有性能差距都来自同步机制本身。
- StringBuilder 可被 JIT 内联优化,逃逸分析支持栈上分配,减少 GC 压力
- StringBuffer 因同步存在,内联受限,锁相关指令抑制 CPU 流水线效率
- 预设容量能缓解扩容开销,但无法绕过方法级同步带来的根本性延迟
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











