StringBuffer通过synchronized关键字保证线程安全,所有修改状态的公开方法均同步,锁住this对象,确保单次操作原子性但不保证组合逻辑的原子性。

所有关键方法都带同步锁
StringBuffer 继承自 AbstractStringBuilder,但所有会改变状态的公开方法都被声明为 synchronized:
public synchronized StringBuffer append(String str)public synchronized StringBuffer insert(int offset, String str)public synchronized void delete(int start, int end)public synchronized StringBuffer reverse()public synchronized String toString()
每次调用时,JVM 自动获取该 StringBuffer 实例的 intrinsic lock。其他线程若尝试调用同一实例的任意同步方法,必须等待锁释放,天然串行化。
只保单次操作原子性,不保组合逻辑
length() 是同步方法,append() 也是同步方法,但 if (sb.length() 并不安全——两个方法之间存在竞态窗口,中间可能被其他线程插入内容。
需要这类“检查-再操作”逻辑时,必须手动加锁:
立即学习“Java免费学习笔记(深入)”;
- 用
synchronized(sb) { ... }包裹整个判断和修改块 - 避免拆解成多个独立同步调用
- 类似场景还包括:先 substring 再 insert、先 charAt 再 setCharAt 等
锁是对象级的,不同实例互不影响
它用的是 this 锁,不是 static 锁:
- sb1 和 sb2 是两个不同的 StringBuffer 对象,多个线程可同时操作它们,完全不阻塞
- 只有多个线程操作同一个实例时,才会排队执行
- 这种设计既守住共享状态的安全边界,又不无谓限制并发
适用场景很明确,别误用
StringBuffer 的线程安全只在“多线程共享并并发修改同一实例”时才有意义:
- 适合做全局日志缓冲区、响应头聚合器、老系统中已存在的跨线程字符串拼接逻辑
- 不适合在 run() 方法里 new 出来仅本线程使用——此时应选 StringBuilder,性能高 80% 左右
- 高并发高频写入(如每毫秒数百次)时,单点锁易成瓶颈,建议改用 ThreadLocal<StringBuilder> 或分段收集后合并


















