stringbuffer 通过 synchronized 关键字修饰所有修改和读取方法,以实例对象为锁,确保线程安全;其底层 char 数组操作被完整封装在同步块内,不暴露裸引用;与 stringbuilder 的唯一区别是同步机制,但仅保证单方法原子性,复合操作仍需外部同步。

StringBuffer 通过内部同步机制实现对共享资源的保护,核心是所有公共修改方法(如 append、insert、delete)都用 synchronized 关键字修饰,确保同一时刻只有一个线程能执行这些操作。
所有关键方法都被 synchronized 修饰
StringBuffer 继承自 AbstractStringBuilder,但对其所有可能改变内部状态的方法(比如 append()、insert()、reverse()、setCharAt() 等)都加了 synchronized。这意味着每次调用这些方法时,线程必须先获取 StringBuffer 实例的对象锁,其他线程需等待锁释放后才能进入。
- 锁对象是 StringBuffer 实例本身(即
this),不是类锁 - 读操作如
length()、charAt()也同步,保证读取时不会看到部分更新的中间状态 - 即使多个线程同时调用不同方法,也会串行执行,避免 char 数组内容错乱
底层 char 数组的操作被整体保护
StringBuffer 内部使用一个可变的 char 数组(来自父类 AbstractStringBuilder)存储字符。扩容、复制、移动等操作都封装在同步方法内,不对外暴露裸数组引用。
- 扩容逻辑(如
ensureCapacityInternal())也在同步块内完成,防止多个线程同时触发扩容导致数组覆盖或越界 - 没有提供直接访问或修改底层数组的 public 方法,杜绝了绕过同步的可能
- 像
toString()返回的是新创建的 String 对象,不影响原 StringBuffer 状态,也不需要同步(但方法本身仍是 synchronized,主要是为了语义一致)
与 StringBuilder 的关键区别
StringBuilder 完全相同的 API 和内部结构,但所有方法都不加 synchronized。这说明 StringBuffer 的线程安全不是靠额外锁工具或 CAS,而是最直接的内置对象锁机制。
- 如果多个线程只读不写,StringBuffer 和 StringBuilder 都安全;但一旦有写操作,未同步的 StringBuilder 就可能产生数据竞争
- 同步带来性能开销,高并发场景下,若需更高吞吐,可考虑用
ThreadLocal<stringbuffer></stringbuffer>或切换到并发更优的方案(如ConcurrentHashMap辅助拼接) - 注意:StringBuffer 仅保证单个方法调用的原子性,不保证多个方法调用的复合操作线程安全(例如
if (sb.length() == 0) sb.append("x")仍需外部同步)
实际使用中的注意事项
虽然 StringBuffer 自带同步,但在复杂业务逻辑中不能盲目依赖它解决所有并发问题。
- 避免在循环里频繁调用同步方法,会加剧线程争用;可先在局部用 StringBuilder 拼接,再一次性 append 到 StringBuffer
- 不要将 StringBuffer 作为全局静态变量随意共享,尤其在 Web 应用中易引发意外共享
- 若需更细粒度控制(如只保护某段操作),应配合
synchronized(sb)块手动加锁,而不是依赖方法级同步
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











