stringbuilder和stringbuffer可变性一致、底层共享动态char[]且扩容逻辑相同,核心区别在于stringbuffer方法加synchronized而stringbuilder无锁,故单线程下stringbuilder快10%–15%,多线程共享时仅stringbuffer安全。

核心就三点:可变性一致,线程安全性不同,性能表现随之分化。
可变性相同,底层都用动态字符数组
StringBuilder 和 StringBuffer 都继承自 AbstractStringBuilder,内部使用非 final 的 char[] 存储内容,支持 append、insert、delete 等原地修改操作,不会像 String 那样每次拼接都新建对象。扩容逻辑也一样:初始容量 16,超出时扩为 原长 × 2 + 2。
线程安全是唯一本质区别
StringBuffer 所有公共方法(如 append、toString)都加了 synchronized 关键字;StringBuilder 完全没加锁。
- 多线程共用同一个 StringBuffer 实例 → 数据不会错乱,比如两个线程同时 append,结果顺序可能不确定但内容不丢失
- 多线程共用同一个 StringBuilder 实例 → 可能出现字符覆盖、长度错乱、甚至抛出 ArrayIndexOutOfBoundsException
- 单线程下两者行为完全一致,只是 StringBuffer 多了一层同步开销
性能差异直接由同步机制决定
在纯单线程场景中,StringBuilder 通常比 StringBuffer 快 10%–15%,因为省去了锁的获取与释放成本。而 String 在频繁修改时性能最差——循环拼接 10000 次,会产生上万个临时对象,触发多次 GC。
- 少量拼接或常量字符串 → 用 String(代码简洁,语义清晰)
- 单线程大量拼接/构建 → 优先选 StringBuilder
- 明确需要多线程共享并修改同一缓冲区 → 才用 StringBuffer
实际选型建议很务实
绝大多数业务代码运行在单线程上下文(如 Spring MVC 的 Controller 方法、Service 层逻辑),此时用 StringBuilder 是默认选择;StringBuffer 更像是一个“备用方案”,只在并发写入同一实例且无法重构为线程隔离时才启用。
面试时如果被问“为什么不用 StringBuffer 代替 StringBuilder”,可以答:同步是重量级保障,不是免费午餐——没并发需求还加锁,等于主动给性能踩刹车。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











