stringbuffer的同步锁是基于实例对象(this)的方法级synchronized,仅保障单个方法调用原子性,不保障跨方法组合操作安全;其append、insert等公开修改方法均声明为public synchronized,由jvm通过acc_synchronized标志自动加锁与释放,非同步方法如length()可并发读取;采用实例锁而非类锁,使不同stringbuffer对象操作互不阻塞,仅同实例多线程访问时串行化;但“检查后执行”等多步逻辑需显式synchronized(sb)保护。

StringBuffer 的同步锁不是“自动兜底”的万能方案,而是基于实例对象锁(this)的方法级同步,只保单个方法调用的原子性,不保跨方法逻辑的安全。
同步锁怎么加在方法上
所有公开修改方法——比如 append()、insert()、delete()、reverse()——都声明为 public synchronized。这意味着:
- 每次调用时,线程必须先获取该 StringBuffer 实例的对象锁(即 this 锁)
- 锁由 JVM 通过字节码中的 ACC_SYNCHRONIZED 标志识别并管理,无需手动写 monitorenter/monitorexit
- 方法执行完毕(含异常退出)后,锁自动释放,不会发生锁泄漏
- 非同步方法如 length()、charAt() 可并发读取,不参与锁竞争
为什么用 this 锁而不是类锁
采用实例锁而非 static synchronized 类锁,是为了最小化锁粒度:
- 两个不同 StringBuffer 对象(sb1 和 sb2)可被多个线程同时操作,互不阻塞
- 只有操作**同一个实例**的多个线程才会排队等待,真正保护共享状态
- 避免全局串行化,兼顾安全性与吞吐量
哪些操作看似安全实则危险
方法本身同步 ≠ 多步逻辑自动受保护。典型陷阱是“检查后执行”或“读-改-写”组合:
- if (sb.length() :length() 和 append() 是两次独立加锁调用,中间可能被其他线程修改 sb
- int len = sb.length(); sb.delete(0, len / 2);:len 取值后 sb 可能已被修改,导致越界或删错
- String s = sb.toString(); s.toUpperCase();:toString() 返回新 String,后续操作与 sb 锁无关
这类场景必须显式同步:synchronized (sb) { ... }
什么时候真该用 StringBuffer
它只在以下条件同时满足时才有存在价值:
- 多个线程**共享同一个 StringBuffer 实例**(例如作为 static 字段、或被多个 Runnable 共同引用)
- 这些线程**并发读写该实例**,而非各自新建后丢弃
- 系统无法重构,需兼容旧有同步语义
反例:循环中 new StringBuffer()、Runnable.run() 里局部创建——此时用 StringBuilder 更高效,性能通常高 2–3 倍。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











