StringBuffer通过方法级synchronized锁住this实例,确保同一时刻仅一个线程执行append、insert、delete、reverse、toString等同步方法,从而防止字符数组越界、长度错乱和内容覆盖;但无法保障多步操作(如check-then-act)的原子性。

StringBuffer 通过方法级 synchronized 锁住实例自身(this),确保同一时刻只有一个线程能执行修改操作,从而防止字符数组错位、长度计数错乱、内容覆盖等数据损坏问题。
同步机制如何起作用
它的所有核心修改方法——append()、insert()、delete()、reverse()、toString()——都声明为 synchronized。这意味着:
- 每次调用时,线程必须先获取该 StringBuffer 实例的对象锁
- 锁未释放前,其他线程对同一实例的同步方法调用会被阻塞
- 单个方法内部对
char[] value和int count的读写是原子的,不会出现“读一半被改”的中间状态
它能防什么,不能防什么
能可靠保障单次操作的完整性:比如两个线程并发 append("x"),最终一定得到两个 "x",不会丢字符、不会越界、不会抛 ArrayIndexOutOfBoundsException。
但无法自动保障多步逻辑的原子性。例如:
立即学习“Java免费学习笔记(深入)”;
if (sb.length() 是典型竞态:<code>length()和append()是两次独立加锁调用,中间可能被其他线程插入操作- 此时需显式同步:
synchronized (sb) { if (sb.length()
真正需要它的前提条件
不是“用了多线程”就要用 StringBuffer,而是必须同时满足:
- 多个线程持有并操作的是同一个 StringBuffer 实例(如 static 字段、被多个 Runnable 共享的成员变量)
- 这些线程会并发读写该实例(不只是各自构造后丢弃)
- 业务逻辑无法重构为线程隔离方式(如改用 ThreadLocal 或不可变片段合并)
使用中容易忽略的关键细节
光用 StringBuffer 不等于万事大吉,还需注意:
- 构造时预设合理初始容量(如
new StringBuffer(1024)),减少扩容时的锁争抢 - 避免在已同步的方法外再套
synchronized(sb),造成重复加锁 -
toString()返回的 String 是不可变的,后续只读可安全跨线程传递 - 若只需最终汇总结果,更推荐各线程用 StringBuilder 独立拼接,最后由单一线程合并


















