stringbuffer通过在所有修改方法上加synchronized实现线程安全,锁的是实例对象而非类,保证同一对象操作串行化,但带来性能开销且不保障复合操作原子性。

答这个问题,关键不是背“加了synchronized”,而是讲清楚为什么加、加在哪、加了之后怎么保证线程安全、又付出了什么代价。
StringBuffer 方法级同步是核心机制
StringBuffer 所有修改内容的方法(如 append()、insert()、delete()、reverse())都被 synchronized 修饰。这意味着:
- 每个方法执行时,会自动获取当前 StringBuffer 实例的对象锁(this monitor)
- 同一时刻,只有一个线程能进入任意一个 synchronized 方法
- 即使多个线程同时调用不同方法(比如线程A调 append、线程B调 delete),也会串行执行,避免内部 char[] 数组被并发修改导致数据错乱(如数组越界、长度不一致、字符覆盖等)
底层依赖的是对象锁,不是类锁
它的 synchronized 是实例方法级别的,锁的是具体对象(this),不是整个 StringBuffer.class。所以:
- 两个不同的 StringBuffer 对象(sb1 和 sb2)可以被不同线程并发操作,互不影响
- 但对同一个 sb 对象的并发调用,会被强制排队,保证操作原子性
- 这种设计兼顾了安全性与基本的并发隔离能力
同步带来的性能开销是真实存在的
每次进入 synchronized 方法都要经历锁获取、可能的阻塞、锁释放过程。尤其在高并发、高频调用场景下:
- CPU 要处理锁竞争,可能引发上下文切换
- 相比 StringBuilder,实测吞吐量通常低 10%–20%
- 如果业务本身是单线程,或者字符串操作不在热点路径上,这个同步就是冗余负担
它不解决外部逻辑的线程安全问题
StringBuffer 只保障自身方法调用的原子性,不负责你代码里的复合操作。例如:
- 错误写法:if (sb.length() == 0) sb.append("default"); —— 这里判断和追加是两步,中间可能被其他线程修改,StringBuffer 不保证这个“判断+操作”的整体原子性
- 正确做法:需要这类逻辑,得由上层用额外同步块或更高级并发工具控制
不复杂但容易忽略:synchronized 是它线程安全的全部根基,没别的魔法。理解这点,就能把原理、取舍、边界都说明白。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











