stringbuffer线程安全依赖方法级synchronized,仅保障单个方法原子性,多步操作需手动加锁;其同步通过实例锁和acc_synchronized字节码实现,而stringbuilder无同步、性能更高但不适用于多线程共享场景。

Java中StringBuffer的线程安全不是“自动万能”的保护伞,而是基于方法级synchronized的有限保障——它只确保单个方法调用的原子性,不覆盖多步逻辑的竞态风险。
同步机制怎么起作用
StringBuffer所有公开修改方法(如append、insert、delete、reverse、setCharAt)都声明为synchronized,意味着:
- 每次调用时,线程必须先获取该StringBuffer实例的对象锁(this)
- 同一时刻,仅一个线程能执行该实例上的任意synchronized方法
- 其他线程若尝试调用,会被阻塞,直到锁被释放
- 底层字节码带ACC_SYNCHRONIZED标志,由JVM直接支持,无需手动加锁语句
安全边界在哪
线程安全仅止于单方法调用。以下常见组合操作不在保护范围内:
- 检查后使用(check-then-act):如if (sb.length() ,两行之间可能被其他线程修改sb
- 读-改-写序列:如int len = sb.length(); sb.delete(0, len/2);,len已失效
- toString()之后的操作:返回的是新String对象,与原sb锁无关;后续对该String的任何操作都不受保护
这类场景必须显式同步:synchronized(sb) { ... }
和StringBuilder到底差在哪
二者API完全一致,核心差异仅在于同步策略:
- StringBuffer:每个修改方法加synchronized,适合多线程共享写入(如日志聚合器、全局配置拼接器)
- StringBuilder:无任何同步,单线程下性能高约80%–100%,是局部变量拼接(如SQL构建、JSON生成)的默认选择
- 二者底层都继承AbstractStringBuilder,共享扩容逻辑(默认容量16,扩容公式为2×旧容量+2)
实际选型与优化建议
不要因“线程安全”就默认选用StringBuffer。应按场景判断:
- ✅ 真需共享可变状态且多线程并发修改 → 用StringBuffer
- ✅ 单线程或方法内局部使用 → 必须用StringBuilder
- ✅ 高并发拼接但不想串行化瓶颈 → 改用ThreadLocal
或ConcurrentLinkedQueue收集再合并 - ✅ 仅需拼接无复杂逻辑 → 优先考虑String.join()、Collectors.joining()等不可变方案
现代JVM虽可能通过逃逸分析消除部分StringBuffer同步,但不应依赖此优化;明确语义比等待JIT更可靠。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











