StringBuffer 并未被淘汰但使用场景大幅收窄,单线程下因 synchronized 开销大而性能不如 StringBuilder,多线程共享时粗粒度锁导致严重竞争,现代开发更倾向无锁、不可变或细粒度并发方案。

StringBuffer 并没有被“淘汰”,而是使用场景大幅收窄——它依然存在、完全可用,只是在绝大多数现代 Java 开发中,已不再是合理首选。
单线程拼接:性能开销纯属冗余
当前主流业务逻辑(如 Web 请求处理、Stream 操作、本地数据组装)基本运行在单线程上下文中。StringBuffer 所有修改方法(append、insert、delete 等)都加了 synchronized,强制获取对象锁。这在单线程里毫无必要:
- 每次调用都要走锁的申请与释放流程,增加 CPU 指令开销
- JIT 编译器难以对 synchronized 方法做深度内联或锁消除
- 基准测试显示,相同拼接逻辑下 StringBuilder 比 StringBuffer 快 10%–15%,高频率拼接(如日志模板、SQL 构建)差距更明显
多线程共享拼接:粗粒度锁导致严重竞争
真正需要跨线程写入同一缓冲区的场景极少。而 StringBuffer 的同步是“对象级全锁”——两个线程哪怕一个往开头 insert、一个往末尾 append,也必须排队执行:
- 无法并行,吞吐量随线程数增长趋近于平缓甚至下降
- toString() 也同步,频繁调用会放大锁争用
- 扩容时涉及数组复制,同步块内执行时间变长,加剧阻塞
更优替代方案已成标准实践
现代开发倾向“避免共享可变状态”,而非“给共享加锁”:
立即学习“Java免费学习笔记(深入)”;
- 各线程独立拼接 → 用 ThreadLocal<StringBuilder>,零竞争、无锁、内存局部性好
- 异步任务收集片段 → 用 ConcurrentLinkedQueue<String> 或 CopyOnWriteArrayList,最终单线程合并
- 已知长度或高频拼接 → new StringBuilder(2048) 预分配容量,避开扩容抖动
- 函数式/不可变风格 → 用 String.join()、Collectors.joining(),语义清晰且线程安全
遗留设计与维护成本不匹配
StringBuffer 是 JDK 1.0 就存在的类,设计初衷是为早期缺乏并发工具的年代提供“开箱即用”的线程安全。如今:
- Java 并发包(java.util.concurrent)提供了更精细、更高性能的协作机制
- Spring、Jackson、MyBatis 等主流框架内部拼接均默认使用 StringBuilder
- 代码审查中若发现 static StringBuffer 或跨 Service 共享 StringBuffer 实例,往往意味着设计缺陷或并发隐患


















