stringbuffer线程安全但性能差,因同步锁粒度粗、扩容双重同步、高并发争抢严重;仅适用于多线程必须共享同一实例且无法线程隔离的低并发场景。

StringBuffer 确实线程安全,但它的性能瓶颈不在“能不能用”,而在于同步机制本身的设计——锁粒度太粗、扩容开销叠加、高并发下争抢严重。它不是过时,而是适用场景非常明确:仅当多个线程必须共享同一个实例、且无法改用线程隔离方案时,才值得考虑。
同步锁粒度粗,导致高并发下排队严重
StringBuffer 所有 public 方法(append、insert、toString 等)都用 synchronized 锁住整个对象。这意味着:
- 哪怕两个线程分别往字符串开头和结尾追加内容,也得串行执行
- 链式调用如 sb.append("a").append("b").append("c") 会进出同步块三次,开销翻倍
- 线程频繁阻塞、唤醒,CPU 时间花在上下文切换上,而非拼接本身
扩容时双重同步放大延迟
当内部 byte[](JDK9+)或 char[](JDK8)容量不足时,StringBuffer 按照 新容量 = 旧容量 × 2 + 2 扩容。这个过程包含两次同步操作:
- 先同步检查当前容量是否足够
- 再同步执行数组复制与替换
- 若多个线程几乎同时触发扩容(如批量日志写入),不仅抢锁,还可能重复拷贝同一份数据
真正适合 StringBuffer 的场景其实很窄
它只在满足以下全部条件时才是合理选择:
- 多个线程确实需要读写同一个 StringBuffer 实例(非只读)
- 业务逻辑无法重构为线程私有拼接 + 最终合并(比如用 ThreadLocal
) - 并发度低(例如定时任务中几个后台线程协作生成配置文本)
- 代码可维护性比几毫秒级吞吐更重要
更实用的替代方案推荐
多数情况下,应优先避开共享 StringBuffer:
- 单线程高频拼接:直接用 StringBuilder,预估初始容量(如 new StringBuilder(4000))减少扩容
-
多线程但可隔离:用 ThreadLocal
,每个线程独享实例,无锁无竞争 - 需最终聚合结果:各线程用 StringBuilder 拼好局部字符串,再用 ConcurrentLinkedQueue 或 StringBuilder.append() 合并
- 极端高并发日志/响应组装:考虑异步缓冲 + 批量刷写,或用 LMAX Disruptor 等无锁队列协调
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











