StringBuilder 与 StringBuffer的区别

一、线程安全

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

七、深度理解

  1. 为什么不安全?

    • StringBuilder 的 countvalue 在多线程下可能被同时修改,导致数据不一致
  2. 为什么性能好?

    • 避免了 synchronized 的锁竞争和上下文切换开销
  3. 最佳实践

    go 复制代码
    // ✅ 推荐:预估容量,减少扩容
    StringBuilder sb = new StringBuilder(256);
    
    // ✅ 推荐:链式调用
    sb.append("Hello").append(" ").append("World");
    
    // ❌ 避免:频繁扩容
    StringBuilder sb = new StringBuilder(); // 会多次扩容
相关推荐
冰糖雪梨dd14 小时前
【JavaScript】 substring()方法详解
开发语言·前端·javascript
liuyao_xianhui14 小时前
动态规划_简单多dp问题_打家劫舍_打家劫舍2_C++
java·开发语言·c++·算法·动态规划
小鸡脚来咯14 小时前
SQL表连接
java·开发语言·数据库
John Song14 小时前
npm查看全局安装了哪些命令
前端·npm·node.js
QC班长15 小时前
如何进行接口性能优化?
java·linux·性能优化·重构·系统架构
聆风吟º15 小时前
直击复杂 SQL 瓶颈:金仓基于代价的连接条件下推技术落地
java·数据库·sql·kingbasees
清汤饺子15 小时前
用了大半年 Claude Code,我总结了 16 个实用技巧
前端·javascript·后端
兆子龙16 小时前
ahooks useMemoizedFn:解决 useCallback 的依赖地狱
java·javascript
曹牧20 小时前
BeanUtils.copyProperties‌
java
QWQ___qwq21 小时前
Java线程安全深度总结:基本类型与引用类型的本质区别
java·安全·面试