stringbuffer 的线程安全靠方法级 synchronized 实现,其内部 char[] 数组本身无同步机制;所有修改方法(如 append、insert)均被 synchronized 修饰,保证原子性与可见性;stringbuilder 结构相同但无 synchronized,性能更高却不安全;单个方法线程安全,但多方法组合操作仍需额外同步。

StringBuffer 的线程安全不依赖于内部缓冲数组本身的结构,而是靠方法级别的 synchronized 修饰实现的。它的 char[] 数组(即内部缓冲区)本身是普通可变数组,没有任何特殊同步机制;真正保障多线程安全的是所有可能修改该数组的方法(如 append、insert、delete、reverse 等)都被声明为 synchronized,确保同一时刻只有一个线程能执行这些操作。
内部缓冲数组只是普通 char[]
StringBuffer 底层使用一个 char[] value 存储字符数据,和 String 内部的 value 字段类似(但 String 的是 final 且不可变)。这个数组本身没有加锁、不使用 volatile、也不采用 CAS,它就是一块普通的堆内存。扩容时(例如调用 ensureCapacity),也只是通过 Arrays.copyOf 创建新数组并赋值给 value —— 这个赋值操作被包裹在 synchronized 方法中,所以不会出现“部分写入”或“引用可见性”问题。
synchronized 方法保证原子性与可见性
所有会读写 value 数组的方法都带有 synchronized 锁(锁对象是 this)。这意味着:
- 多个线程调用
append("a")时,实际是串行执行的,不会出现字符错乱或数组越界 - 一个线程修改了
count(当前有效字符数)和value数组内容,退出同步块后,其他线程进入时一定能看到最新值(JVM 内存模型保证 synchronized 的释放-获取语义) - 即使底层数组发生扩容重分配,整个过程也被锁保护,外部永远看不到中间不一致状态
对比 StringBuilder:唯一区别就是 synchronized
StringBuilder 和 StringBuffer 的内部结构几乎完全一样(同样用 char[] value + int count),差别仅在于方法是否加 synchronized:
- StringBuffer:所有修改方法都是 synchronized,适合多线程场景
- StringBuilder:对应方法无 synchronized,性能更高,但不保证线程安全
换句话说,把 StringBuffer 所有 public 方法的 synchronized 关键字去掉,它就变成了 StringBuilder —— 缓冲数组本身不需要任何改动。
注意:线程安全 ≠ 操作组合安全
StringBuffer 保证单个方法调用的线程安全,但不保证多个方法调用组成的逻辑是原子的。例如:
❌ 不安全(竞态仍可能发生):if (sb.length() == 0) sb.append("default");
因为 length() 和 append() 是两个独立的 synchronized 方法,中间可能被其他线程修改。若需这种复合操作的原子性,仍需手动加锁或改用更高层同步机制。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











