StringBuffer能保证线程安全,因其所有修改方法(如append、insert、delete)均被synchronized修饰,通过方法级同步确保同一时刻仅一个线程可操作共享char[]数组,避免并发写入导致的数据错乱。

多线程环境下拼接字符串,核心是避免多个线程同时修改同一对象导致数据错乱。StringBuffer 就是专为此设计的——它通过 synchronized 关键字保障线程安全,适合在并发场景中直接复用同一个实例。
为什么 StringBuffer 能保证线程安全
StringBuffer 的所有修改方法(如 append、insert、delete)都加了 synchronized 锁。这意味着:当一个线程正在调用 sb.append("A") 时,其他线程无法同时进入该方法体,必须等待锁释放。底层共享的 char[] 数组不会被并发写入破坏,结果始终可预期。
- 不是靠“不可变”实现安全(String 不可变但不适用于拼接场景)
- 也不是靠每次新建对象(那样性能极差)
- 而是靠方法级同步,兼顾安全性与对象复用
典型多线程拼接场景示例
比如多个线程向日志缓冲区追加内容,共用一个 StringBuffer 实例:
StringBuffer logBuffer = new StringBuffer();
Thread t1 = new Thread(() -> logBuffer.append("[INFO] Task1 done\n"));
Thread t2 = new Thread(() -> logBuffer.append("[WARN] Task2 slow\n"));
t1.start(); t2.start();
t1.join(); t2.join();
System.out.println(logBuffer.toString()); // 输出顺序不确定,但内容不会损坏
注意:虽然拼接结果顺序可能因线程调度而异,但每个 append 操作的内容完整、无截断、无字符错位——这就是线程安全的体现。
立即学习“Java免费学习笔记(深入)”;
使用时的关键注意事项
- 不要在 synchronized 块外对 StringBuffer 做非原子操作(例如先 length() 再 append,中间可能被其他线程插入)
- 避免在高竞争场景下过度依赖单个 StringBuffer 实例,必要时可考虑分段缓冲或使用并发容器
- 如果只是读取 toString() 结果,无需额外同步;但若需多次 append 后统一处理,建议在拼接完成后一次性 toString()
- 不要误用 StringBuilder 替代——它没有同步机制,在多线程中会出现字符丢失、乱序甚至数组越界异常
和 StringBuilder 的本质区别
两者 API 几乎完全一致,差异仅在于并发控制:
- StringBuffer:方法带 synchronized,适合多线程共享实例
- StringBuilder:方法无锁,单线程快约 10%–15%,多线程下行为未定义
选错会导致难以复现的偶发性错误,而不是编译报错——这点特别容易被忽略。


















