stringbuffer 的线程安全依赖每个公开方法加 synchronized 锁住 this,保障单方法原子性但不保证多步操作安全;仅当多线程共享并并发读写同一实例时才需使用,否则优先选 stringbuilder 或 threadlocal。

Java 中 StringBuffer 的线程安全,靠的是每个公开修改方法(如 append、insert、delete、reverse、toString)都加了 synchronized 修饰符,锁住当前实例对象(this),确保同一时刻只有一个线程能执行这些操作。
同步机制怎么起作用
每次调用 StringBuffer 的 synchronized 方法时,JVM 会尝试获取该实例的对象锁。如果锁正被其他线程持有,当前线程就会阻塞等待。这种设计保障了单个方法内部的原子性:
- 字符数组扩容、长度更新、缓存清理(toStringCache)等底层动作,全部包裹在同步块内
- 不会出现 count 字段错乱、数组越界或内容覆盖等数据损坏问题
- 所有 public 方法(包括 length()、capacity())都带 synchronized,读写操作也受锁保护
单方法安全 ≠ 多步操作安全
方法级同步不能自动延伸到跨方法的业务逻辑。典型风险是“检查后使用”(check-then-act)竞态:
Java JDK 25 来自 OpenJDK 官方归档,版本为 JDK 25,本条下载地址已指向官方 Windows x64 zip 安装包直链,适合调试旧项目或兼容旧版 Java 运行环境。
- sb.length() 和 sb.append("x") 是两次独立的同步调用,中间可能被其他线程修改 sb
- 必须手动用 synchronized(sb) { ... } 包裹整个判断+操作逻辑
- 即使 toString() 是同步的,它返回的是新 String 对象,后续对该 String 的任何操作都不再受 StringBuffer 锁保护
什么时候才真正需要 StringBuffer
不是“多线程环境”就该用 StringBuffer,关键看是否满足两个条件:
- 多个线程**共享同一个 StringBuffer 实例**(例如 static 字段、被多个 Runnable 共同引用)
- 多个线程**并发读写**该实例(不只是各自拼接后丢弃)
- 反例:在 run() 方法里每次 new StringBuffer(),仅本线程使用——此时用 StringBuilder 更快,性能通常高 2–3 倍
性能代价与更优替代方案
每个 synchronized 方法都有锁竞争开销,在高并发写入场景下吞吐量明显下降:
- 优先考虑 ThreadLocal
:每个线程独享实例,零锁、高性能 - 用 ConcurrentLinkedQueue
收集片段,最后由单一线程合并 - 设计上避免共享:让字符串拼接局限于单线程上下文,从源头消除同步需求
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










