stringbuffer因全方法同步导致性能低于stringbuilder。其粗粒度锁、无竞争时仍执行锁流程、tostring缓存受同步保护等开销,使单线程慢10%–15%,高并发下差距达5倍。

因为锁本身就有执行成本,不是“没开销的开关”。哪怕没有线程竞争,JVM 仍要走完整的锁流程——获取 monitor、插入内存屏障、维护锁状态,这些操作在高并发下会迅速放大。
锁粒度太粗,排队不可避免
StringBuffer 几乎所有 public 方法(append、insert、delete、toString 等)都加了 synchronized,锁的是整个对象实例。这意味着:
- 两个线程哪怕往不同位置追加内容,也必须串行执行
- 一个线程调用 append(),另一个线程想读 length() 或调用 reverse(),同样得等
- 连续链式调用如 sb.append("a").append("b").append("c"),会反复进出锁,触发三次 monitor 进入/退出
锁机制在无竞争时也不跳过
即使单线程调用 StringBuffer,JVM 仍要执行:
- 检查锁状态(偏向锁→轻量级锁→重量级锁的判断路径)
- 插入读写内存屏障,保证字段可见性
- 每次同步块进出都生成 monitorenter / monitorexit 字节码指令
这些逻辑无法被 JIT 编译器完全优化掉,属于“白付的开销”。
toString 缓存反而拖慢吞吐
JDK 9+ 中 StringBuffer 的 toString() 依赖 toStringCache 字段做缓存,但这个字段本身也要被 synchronized 保护:
- 多线程频繁调用 toString() 时,缓存常被置为 null,复用率极低
- 而 StringBuilder 每次都直接复制 char[],看似多一次数组拷贝,实则省去了锁检查 + 缓存一致性维护的综合成本
- 在高频拼接 + 频繁转字符串的场景下,这个差异会快速累积
对比 StringBuilder 更凸显瓶颈
StringBuilder 完全绕开锁机制:
- 方法调用是普通 invokevirtual,无 monitor 指令
- 底层复用 AbstractStringBuilder 的 char[],扩容逻辑一致,仅差在同步层
- 实测:单线程快 10%–15%,高并发无竞争时差距可达 5 倍
这不是 synchronized 写得不好,而是它为线程安全付出的代价,在高并发争用场景下显得特别重。











