StringBuffer 的线程安全基于 synchronized 实例方法实现对象级锁,保障单方法原子性但不保证组合操作原子性,适用于多线程共享同一实例场景,性能低于 StringBuilder。

Java 中 StringBuffer 的线程安全不是一种“设计模式”,而是一种基于 synchronized 方法 的原生同步机制——它不依赖外部模式,而是靠每个公开修改方法(如 append、insert、delete、reverse)都加 synchronized 修饰符,锁住 this 实例来实现线程安全。
同步粒度:对象级锁,非类级或静态锁
StringBuffer 使用的是实例对象锁(this),不是 static synchronized 或 Class 对象锁。这意味着:
- 两个不同的 StringBuffer 实例(sb1 和 sb2)可被多个线程同时操作,互不干扰
- 只有当多个线程操作同一个实例时,才会因竞争同一把 monitor 锁而串行执行
- 这种设计符合“最小保护范围”原则:只锁共享状态本身,不扩大作用域
安全边界:单方法原子性,不保组合逻辑
synchronized 方法保障的是单次调用的原子性,比如一次 append() 不会中途被打断、不会出现 count 错乱或数组越界。但它不保证多步操作的原子性:
-
if (sb.length() < 10) sb.append("x");—— length() 是非同步方法,中间可能被其他线程修改 -
int len = sb.length(); sb.delete(0, len / 2);—— 第二步执行时,len 已失效 - 这类“检查-后-执行”(check-then-act)场景必须手动同步:
synchronized(sb) { ... }
Builder 场景中的自然复用
利用 StringBuffer 天然同步特性,可构建线程安全的 Builder 类,无需额外加锁:
立即学习“Java免费学习笔记(深入)”;
- Builder 内部持有一个 private final StringBuffer 字段
- 所有 addXxx() 方法调用 stringBuffer.append(...) 后返回 this,支持链式调用
- build() 调用 toString() 获取最终字符串,不暴露 StringBuffer 引用
- 注意:Builder 实例本身仍是可变对象,若被多线程共享,需确保其使用方式合理(如配合 ThreadLocal 或显式同步)
性能代价与适用前提
同步开销真实存在,不能为“安全”而默认选用:
- 单线程下,StringBuffer 比 StringBuilder 慢约 50%–85%,源于每次调用都触发 monitor enter/exit
- 只有在多个线程必须反复读写同一个 StringBuffer 实例且无法通过 ThreadLocal、局部变量或不可变结果传递规避时,才真正需要它
- 典型合理场景:全局日志缓冲器、遗留系统中无法重构的并发拼接逻辑
- 多数业务中,用 StringBuilder + 方法内局部变量即可,更轻量、更高效


















