stringbuffer 通过将 append、insert、delete 等方法声明为 synchronized 实现线程安全,确保多线程调用时操作原子性;其底层 char[] 数组的扩容与写入均受锁保护,避免数据错乱;与无同步的 stringbuilder 相比,它牺牲性能换取安全性。

StringBuffer 通过内置的 synchronized 关键字保证多线程下的字符串连接安全。它不是靠外部加锁或额外同步机制,而是将关键方法(如 append、insert、delete)直接声明为同步方法,使每次操作都独占对象锁,从而避免并发修改导致的数据错乱。
所有修改方法都是 synchronized 的
StringBuffer 继承自 AbstractStringBuilder,但对其所有可能改变内部字符数组(value)的方法都加了 synchronized 修饰符。例如:
public synchronized StringBuffer append(String str)public synchronized StringBuffer insert(int offset, String str)public synchronized StringBuffer delete(int start, int end)
这意味着:多个线程同时调用同一个 StringBuffer 实例的 append 方法时,JVM 会确保它们串行执行,一个线程进入后,其他线程必须等待锁释放才能继续。
底层共享 char[] 数组,但访问受锁保护
StringBuffer 内部使用一个可变的 char[] value 存储内容,扩容(如 ensureCapacity)和写入(如 getChars、copyValueOf)都发生在同步块内。即使多个线程触发扩容,也不会出现数组复制不一致、索引越界或部分写入丢失等问题。
例如两个线程同时执行 sb.append("a") 和 sb.append("b"),最终结果一定是 "ab" 或 "ba"(顺序取决于调度),但绝不会是 "a"、"b"、空字符串或乱码——因为每次 append 都完整完成“检查容量→复制/扩容→写入→更新 count”这一原子过程。
与 StringBuilder 的核心区别就是同步性
StringBuilder 完全相同的代码结构,只是去掉了 synchronized。因此:
- 单线程场景下,StringBuilder 性能更高(无锁开销)
- 多线程共享同一实例时,StringBuilder 可能产生不可预测结果(如
count错误、数组越界、字符串截断) - StringBuffer 则天然支持线程安全的拼接,无需调用方额外同步
注意:StringBuffer 的线程安全仅针对自身实例的操作。如果多个线程还同时读取并依赖中间状态(比如一边 append 一边调用 toString() 做判断),仍需根据业务逻辑评估是否需要更上层的协调。
实际使用建议
虽然 StringBuffer 是线程安全的,但在现代 Java 开发中应谨慎选择:
- 优先考虑是否真的需要多个线程共用同一个 StringBuffer 实例;多数情况下,各线程用各自的 StringBuilder 更高效
- 若必须共享,确认没有其他非同步方式修改该实例(如反射篡改
value) - 高并发频繁拼接场景,可考虑使用
ThreadLocal<stringbuffer></stringbuffer>避免锁竞争 - JDK 9+ 中,字符串拼接更多由编译器优化为
invokedynamic+StringConcatFactory,对简单拼接已不依赖 StringBuffer
它的线程安全性是明确且可靠的,但代价是同步带来的性能折损。理解这点,才能在安全与效率之间做出合理取舍。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











