单线程字符串拼接首选stringbuilder,因其无synchronized开销、性能比stringbuffer高10%–15%;多线程真共享同一实例时才用stringbuffer;避免循环中用string+=、不将stringbuilder设为共享bean、不盲目替换为stringbuffer、预估容量防频繁扩容。

直接看三点:字符串要不要改、改的人是不是只有一个线程、改的时候多个线程会不会共用同一个对象。
单线程拼接,无条件选 StringBuilder
日常开发里 90% 的字符串拼接都在单线程中完成,比如组装日志、生成 SQL、构造 JSON、拼接 URL 参数等。StringBuilder 没有 synchronized 开销,实测比 StringBuffer 快 10%–15%,是默认首选。
- 初始化时尽量预估容量,比如拼 500 条记录、每条平均 60 字符,就用 new StringBuilder(30000),避免多次扩容复制数组
- 链式调用很自然:sb.append("id=").append(id).append("&name=").append(name)
- 定义为方法内局部变量最安全,不跨线程、不共享、用完即弃
多线程真共享同一个实例,才考虑 StringBuffer
StringBuffer 不是“更稳妥的 StringBuilder”,而是专为一种特定并发模式设计的:多个线程确实共用同一个对象,并同时调用 append、insert 等方法。
- 它的每个 public 修改方法都加了 synchronized,能保证单个操作原子性
- 但复合逻辑(比如先判断长度再删除)仍需额外加锁,它不解决业务级同步问题
- 典型场景极少,如老系统中作为全局日志缓冲器被注入到多个服务类中
现代替代方案比 StringBuffer 更常用
真正需要 StringBuffer 的场景正在快速减少。现在更推荐两种更清晰、更可控的方式:
- 把 StringBuilder 放在方法参数里显式传递:每个线程自己 new 一个,拼完传出去,彻底规避共享
- 用 ThreadLocal 封装 StringBuilder:每个线程独享一份,兼顾性能与隔离性,适合高频复用的工具类
别踩这些坑
常见误用会直接带来性能下降或数据错乱:
- 在 for 循环里写 String s += "x" —— 每轮都新建对象,GC 压力飙升
- 把 StringBuilder 设为 Spring Bean 的成员变量,被多个请求线程复用 —— 非线程安全,结果串行错乱
- 以为 StringBuffer “更安全”就全项目统一替换 —— 白白承担同步开销,拖慢单线程主路径
- 忽略初始容量,在大文本拼接中让 StringBuilder 反复扩容(16 → 34 → 70 → 142…),浪费 CPU 和内存
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











