stringbuffer线程安全依赖方法级synchronized锁住实例对象,确保单个操作原子性,但多步操作需显式同步;仅当多线程共享并并发读写同一实例时才真正必要,否则应优先选用stringbuilder或threadlocal优化性能。

Java 中 StringBuffer 的线程安全,靠的是方法级 synchronized 锁住整个实例对象,确保同一时刻只有一个线程能执行它的修改操作。但这不等于“所有场景都自动安全”,关键得看怎么用。
同步机制怎么起作用
StringBuffer 的 append、insert、delete、reverse、toString 等公开方法,全部声明为 synchronized。这意味着:
- 每次调用这些方法时,都会尝试获取该 StringBuffer 实例自身的对象锁(
this) - 若锁已被其他线程持有,当前线程会阻塞等待,直到锁释放
- 单个方法内部的操作(比如一次 append)是原子的,不会出现字符数组越界、长度错乱或内容覆盖
单方法安全 ≠ 多步操作安全
方法本身同步,不代表跨方法的逻辑自动受保护。常见陷阱是“先检查、再操作”:
- 错误写法:
if (sb.length() —— length() 和 append() 是两个独立同步方法,中间可能被其他线程修改 sb - 正确做法:用显式同步块包裹整个判断+操作逻辑:
synchronized (sb) {<br> if (sb.length() sb.append("x");<br> }<br>}
什么时候真该用 StringBuffer
不是“多线程”就一定需要 StringBuffer。它只在以下情况真正必要:
- 多个线程**共享同一个 StringBuffer 实例**(如作为类的 static 字段、或被多个 Runnable 共同引用)
- 多个线程**并发读写**该实例(不只是各自拼接后丢弃)
- 遗留系统依赖其同步语义,且重构成本过高
反例:在 for 循环或 run() 方法里每次 new StringBuffer,仅本线程使用——这时用 StringBuilder 更快,性能通常高 2–3 倍。
性能代价与更优替代方案
每个 synchronized 方法都有锁竞争开销,在高并发写入场景下明显拖慢吞吐量。可考虑:
-
ThreadLocal
:每个线程独享 StringBuilder 实例,零锁、高性能 -
不可变 + 并发收集:用 ConcurrentLinkedQueue
收集片段,最后由单一线程合并 - 避免共享:设计上让字符串拼接局限于单线程上下文,从根本上消除同步需求
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











