String不可变故线程安全但效率最低;StringBuilder线程不安全但单线程下最快;StringBuffer通过synchronized保证线程安全,但同步开销使其效率居中。

直接看核心差异:线程安全和执行效率是绑定在一起的,不是独立指标。String 本身不可变,天然线程安全但效率最低;StringBuilder 非线程安全,单线程下最快;StringBuffer 用 synchronized 保障线程安全,但同步开销拖慢速度。
线程安全性怎么来的
String 的线程安全来自不可变性——内部 char[] 被 final 修饰,所有操作(如 concat、replace)都返回新对象,原对象不会被修改,多个线程读取同一 String 实例完全无冲突。
StringBuffer 的线程安全靠方法级 synchronized 实现,比如 append()、insert()、delete() 等关键方法都加了锁,确保多线程调用时不会出现数据错乱。
StringBuilder 所有方法都没有 synchronized,多个线程同时调用 append() 可能导致 count 值错乱、value 数组越界或内容覆盖——这不是“偶尔出错”,而是明确不保证行为正确。
执行效率为什么这样排:StringBuilder > StringBuffer > String
效率差异本质是内存操作方式不同:
- String:每次拼接(如 str += "x")都新建对象、复制字符数组、触发 GC,频繁操作会明显卡顿;
- StringBuffer / StringBuilder:共用 AbstractStringBuilder 底层,直接在原有 char[] 上扩展内容,只在扩容时才复制一次数组;
- StringBuilder 比 StringBuffer 快:省去了同步锁的获取/释放、内存屏障、竞争等待等开销,实测通常快 10%–15%。
什么场景该选哪个
不用死记规则,按实际运行环境判断:
- 字符串拼接只发生在单个方法内、或仅由一个线程操作 → 用 StringBuilder;
- 同一个 StringBuffer 实例被多个线程共享并并发修改(如日志缓冲器、全局配置构建器)→ 必须用 StringBuffer;
- 只是拼一次、赋值后就不再改(如 message = "Hello " + name)→ 直接用 String,编译器会自动优化为 StringBuilder;
- 需要线程安全又不愿牺牲太多性能 → 不要用 StringBuffer,改用 ThreadLocal
或 ConcurrentHashMap 等更高阶方案。
一个小验证技巧
想确认某段代码是否真有线程风险?把 StringBuilder 换成 StringBuffer 运行对比:
- 如果结果稳定一致,说明当前没并发问题,StringBuilder 就够用;
- 如果换完后输出变少、乱码、抛 ArrayIndexOutOfBoundsException,大概率是多线程干扰了 count 和 value 的协同更新——这时必须上 StringBuffer 或重构并发逻辑。










