一、线程安全
StringBuilder线程不安全的,StringBuffer线程安全
StringBuffer(线程安全)
java
public class StringBuffer extends AbstractStringBuilder {
// 所有修改方法都加 synchronized 锁
public synchronized StringBuffer append(String str) {
super.append(str);
return this;
}
public synchronized int length() {
return count;
}
public synchronized void setCharAt(int index, char ch) {
// ...
}
}
StringBuilder(非线程安全)
scala
public class StringBuilder extends AbstractStringBuilder {
// 无 synchronized 修饰
public StringBuilder append(String str) {
super.append(str);
return this;
}
public int length() {
return count;
}
}
二、继承关系
dart
java.lang.Object
2 └── java.lang.AbstractStringBuilder
3 ├── java.lang.StringBuilder
4 └── java.lang.StringBuffer
两者都继承自 AbstractStringBuilder,共享大部分底层实现代码
三、核心字段(AbstractStringBuilder)
java
abstract class AbstractStringBuilder implements Appendable, CharSequence {
2 // 存储字符的数组
3 char[] value;
4
5 // 当前已使用的字符数量
6 int count;
7
8 // ...其他方法
9}
注意 :JDK 9+ 之后,String 改用 byte[] + 编码标记(Compact Strings),但 StringBuilder/StringBuffer 仍主要使用 char[]
四、扩容机制(核心原理)
scss
// AbstractStringBuilder 中的扩容逻辑
private void expandCapacity(int minimumCapacity) {
// 新容量 = 原容量 × 2 + 2
int newCapacity = (value.length + 1) * 2;
// 如果新容量仍不够,则使用最小需求容量
if (newCapacity < minimumCapacity) {
newCapacity = minimumCapacity;
}
// 处理溢出情况
if (newCapacity < 0) {
if (minimumCapacity < 0) {
throw new OutOfMemoryError();
}
newCapacity = Integer.MAX_VALUE;
}
// 创建新数组并复制
value = Arrays.copyOf(value, newCapacity);
}
扩容规则
场景
扩容策略
默认构造
初始容量 16
容量不足
newCapacity = (oldCapacity + 1) * 2
指定容量构造
初始容量 = 指定值
五、性能对比测试
操作
String
StringBuffer
StringBuilder
10万次拼接
~3000-5000ms
~15-30ms
~10-20ms
原因
每次创建新对象
同步锁开销
无锁开销
六、源码核心差异总结
维度
StringBuffer
StringBuilder
类修饰
final class
final class
继承
AbstractStringBuilder
AbstractStringBuilder
方法修饰
synchronized
无同步
底层数组
char[] value
char[] value
扩容公式
(oldCapacity + 1) * 2
(oldCapacity + 1) * 2
默认容量
16
16
序列化
实现 Serializable
实现 Serializable
七、深度理解
-
为什么不安全?
- StringBuilder 的
count和value在多线程下可能被同时修改,导致数据不一致
- StringBuilder 的
-
为什么性能好?
- 避免了 synchronized 的锁竞争和上下文切换开销
-
最佳实践:
go// ✅ 推荐:预估容量,减少扩容 StringBuilder sb = new StringBuilder(256); // ✅ 推荐:链式调用 sb.append("Hello").append(" ").append("World"); // ❌ 避免:频繁扩容 StringBuilder sb = new StringBuilder(); // 会多次扩容