优先选 StringBuilder,仅当多线程共享同一实例并发修改时才用 StringBuffer;单线程下 StringBuffer 无谓加锁拖慢性能;预设容量可减少扩容开销;循环中 String 拼接是性能陷阱,须避免。

选 StringBuffer 还是 StringBuilder,关键看线程访问方式,不是看“要不要安全”,而是看“有没有并发修改”。
单线程场景:无条件选 StringBuilder
方法内创建、只在当前线程使用、拼接完就转成 String 返回——这种最常见的情况,StringBuilder 是唯一合理选择。它和 StringBuffer 底层完全一样(都继承 AbstractStringBuilder,扩容逻辑、字符数组操作一致),唯一区别是没加 synchronized。实测 10 万次 append,快 10%–20%,高并发测试中差距还会拉大。用 StringBuffer 在这种场景下,等于主动给代码加锁、拖慢执行、浪费 CPU。
多线程共享同一实例时:才考虑 StringBuffer
只有当一个 StringBuffer 对象被多个线程直接持有并反复调用 append、delete 等方法时,同步才有意义。比如某些老式日志工具把 StringBuffer 作为静态成员或全局缓存,多个线程往里写。这时 StringBuilder 会出错——数据错乱、长度异常、甚至抛出 ArrayIndexOutOfBoundsException。但要注意:这种设计本身已过时,现代做法更倾向用 ThreadLocal
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
别忽略容量预设这个小动作
无论选哪个,如果能估算最终长度,初始化时指定 capacity 能显著减少扩容次数。默认是 16,拼接 5000 字符要扩容七八次,每次都要复制数组。写成 new StringBuilder(8192) 或 new StringBuffer(8192),性能提升肉眼可见。但别过度预估,设成 100 万却只用 2000 字符,就是浪费堆内存。
立即学习“Java免费学习笔记(深入)”;
String 拼接不是备选项,而是陷阱
循环里用 str += "x" 或频繁 concat,不管用 StringBuffer 还是 StringBuilder 都救不了。JVM 虽对单次拼接自动优化成 StringBuilder,但循环中每次 += 都会新建 StringBuilder → append → toString → 弃旧对象,1 万次就产生上万个临时 String,GC 压力陡增。这种写法该删就删,不要想着“换 StringBuffer 就行”。


















