StringBuffer线程安全但性能低,因所有修改方法加synchronized锁住this实例,导致高并发下锁竞争严重;StringBuilder无同步,单线程性能更优;线程安全不等于业务逻辑安全。

高并发下用 StringBuffer 并不天然“安全又高效”,它只是线程安全,但性能会明显拖慢——同步锁是瓶颈,不是保障。真正需要的是根据共享范围、操作粒度和并发强度做精准判断,而不是默认选 StringBuffer。
StringBuffer 的同步到底锁住了什么
StringBuffer 所有修改方法(append、insert、delete、reverse)都加了 synchronized,锁的是当前实例对象(this)。这意味着:
- 同一时刻,只有一个线程能执行它的任意一个同步方法
- 多个线程调用不同方法(比如一个 append,一个 delete)也会排队等待
- toString() 虽然也同步,但返回的是新 String 对象,后续对该 String 的操作不再受锁保护
高并发场景下 StringBuffer 的真实开销
在 JDK 17、8 核 CPU 下做 100 万次 append 测试,StringBuffer 比 StringBuilder 慢约 2–3 倍;当并发线程数超过 4,吞吐量增长几乎停滞,CPU 大量时间花在锁竞争和线程阻塞上。这不是“稍慢”,而是可测量的性能拐点。
更关键的是:单个方法同步 ≠ 业务逻辑安全。例如判断长度再追加,两步之间存在竞态窗口:
立即学习“Java免费学习笔记(深入)”;
❌ 错误写法if (buf.length()
必须显式同步整个逻辑块:synchronized (buf) { if (buf.length()
比 StringBuffer 更适合高并发的替代方案
多数高并发字符串拼接场景,其实不需要共享可变缓冲区。更优解往往更轻量:
- ThreadLocal<StringBuilder>:每个线程独享实例,零锁开销,复用率高,适用于日志格式化、SQL 构建等典型场景
- 不可变拼接 + 并发收集:用 ConcurrentLinkedQueue 或 CopyOnWriteArrayList 收集片段,最后由单一线程合并,适合异步聚合类任务
- 预分配容量 + StringBuilder:已知最终长度时,new StringBuilder(estimatedSize),避免扩容抖动,单线程内极致高效
什么时候才真该用 StringBuffer
仅限以下三类情况之一成立时:
- 多个线程长期共享同一个 StringBuffer 实例,并频繁并发修改(如老系统中全局日志缓冲器)
- 无法重构为无状态设计,且已有代码强依赖其 synchronized 语义
- 并发写入频率极低(如每秒几次),但要求绝对线程安全,且不愿引入额外结构
其余所有情况——包括局部变量拼接、接口响应组装、循环内构建——都应优先用 StringBuilder 或 ThreadLocal 方案。



















