stringbuffer性能损耗主要源于同步机制:方法级synchronized导致无竞争时仍需执行锁指令、内存屏障及锁状态检查,单线程即比stringbuilder慢10%–15%;扩容双重同步易引发重复拷贝;tostring缓存受锁保护反而降低复用率。

StringBuffer 的性能损耗主要来自同步机制本身,不是它“写得不好”,而是线程安全的设计必然带来开销。关键不在有没有锁,而在锁怎么用、用得多不多。
方法级 synchronized 锁住整个对象
所有 public 修改方法(append、insert、delete、reverse、toString)都加了 synchronized,锁对象是 this 实例。这意味着:
- 哪怕两个线程操作完全不重叠的位置,也必须排队执行
- 一次链式调用如 sb.append("a").append("b").append("c") 会进出锁三次
- 连只读的 length() 虽然没加锁,但 toString() 和 reverse() 这类方法仍需抢同一把锁
无竞争时也无法跳过锁流程
即使单线程运行,JVM 仍要走完整锁机制:
- 执行 monitorenter / monitorexit 字节码指令
- 插入内存屏障,保证字段可见性
- 检查偏向锁状态、升级轻量级/重量级锁的判断逻辑
这些操作无法被 JIT 完全优化掉,实测单线程下就比 StringBuilder 慢 10%–15%。
扩容过程触发双重同步
当内部 char[] 不足时,扩容分两步走,且每步都同步:
- 先同步检查容量是否足够
- 再同步执行数组复制与替换(newCapacity = old × 2 + 2)
- 高并发下多个线程可能几乎同时触发扩容,造成重复拷贝和更激烈的锁争用
toString 缓存受同步保护反而拖累吞吐
JDK 9+ 引入 toStringCache 字段缓存结果,但这个缓存本身也要被 synchronized 保护:
- 多线程频繁调用 toString() 时,缓存常被置为 null,复用率极低
- StringBuilder 每次直接复制 char[],看似多一次拷贝,实则省去了锁检查 + 缓存一致性维护的综合成本
- 在高频拼接 + 频繁转字符串场景下,这个差异会快速放大
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











