stringbuffer线程安全以性能为代价,所有关键方法加synchronized锁整个实例,确保多线程并发修改数据一致,但单线程比stringbuilder慢10%–15%,仅在真正共享同一实例并发修改时才需使用。

StringBuffer 的线程安全是以性能为代价换来的,它在单线程下明显比 StringBuilder 慢,但能保证多线程并发修改时的数据一致性。
线程安全的实现方式
StringBuffer 所有关键方法(如 append、insert、delete)都加了 synchronized 修饰符,锁的是整个对象实例。这意味着同一时刻只能有一个线程执行这些操作,其他线程必须等待——这带来了同步开销,也限制了并发吞吐量。
- 锁粒度粗:不是按字符或段落加锁,而是整个方法调用期间独占对象
- 即使多个线程操作各自独立的 StringBuffer 实例,只要方法同步,仍存在锁竞争可能(尤其在高并发池化场景)
- 不可靠的“安全假象”:若业务逻辑涉及多个 StringBuffer 方法调用组成原子操作(如先 length() 再 append()),仅靠单个方法同步仍需额外同步控制
单线程效率为什么更低
没有共享变量竞争时,synchronized 依然触发 JVM 的监视器进入/退出流程,包括内存屏障、锁获取与释放等底层操作。实测表明,在纯单线程字符串拼接中,StringBuffer 比 StringBuilder 慢约 10%–15%。
- 相同扩容策略(初始容量 16,扩容公式:新容量 = 旧容量 × 2 + 2)
- 底层都继承自 AbstractStringBuilder,核心逻辑(如数组复制、字符拷贝)完全一致
- 性能差距几乎全部来自同步机制本身,而非算法或结构差异
什么情况下才该用 StringBuffer
只有当多个线程真正共享并**并发修改同一个 StringBuffer 实例**时,才需要它的线程安全性。这类场景其实很有限。
- 典型例子:全局日志缓冲器、跨线程配置构建器、被多个 Worker 共享并追加内容的文本收集器
- 反例:方法内局部创建、用完即弃的 StringBuffer —— 完全没必要,用 StringBuilder 更合适
- 更优替代:若需在多线程中高效拼接,优先考虑每个线程用独立 StringBuilder,最后合并;或使用 ThreadLocal
避免锁又不浪费对象
实际选型建议
不要因为“可能多线程”就默认选 StringBuffer。绝大多数 Java 应用中的字符串拼接发生在方法栈内、局部变量作用域中,天然线程隔离。
- 95% 以上场景:直接用 StringBuilder,性能好、语义清晰
- 确认多线程共享且无法重构为线程私有时:才升级为 StringBuffer
- 永远避免:for 循环里用 + 拼接 String,它会隐式创建大量临时对象,GC 压力远超同步开销
- 小技巧:预设容量(new StringBuilder(1024))可减少数组扩容次数,对 StringBuffer 同样适用
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











