String、StringBuffer、StringBuilder的应用场景

结论

String:不需要修改字符串,或者修改次数极少 。(String的+=其实不保证线程安全,String的+=操作底层是StringBuilder实现的,线程不安全)

StringBuffer:需要频繁修改字符串,多线程场景,需要保证线程的安全。

StringBuilder:需要频繁修改字符串,单线程场景,需要修改速度快。

原因

为什么String的访问速度快,为什么不能修改

String底层是一个常量,访问一个常量很快的,常量不支持修改。

java 复制代码
private final char value[]

既然String不能被修改,那+=是怎么回事

java 复制代码
public class Main {
    public static void main(String[] args) {
        String s = "123";
        s += "456";
        System.out.println(s);
    }
}

输出

out 复制代码
123456

这样看起来,好像是在s后面添加了字符串"456",但是实际上,是改变了s的引用。

下面这段代码可以验证,s已经不是之前的s了。

java 复制代码
public class Main {
    public static void main(String[] args) {
        String s = "123";
        String b = s;
        System.out.println(b == s);
        s += "456";
        System.out.println(b);
        System.out.println(b == s);
    }
}

输出

out 复制代码
true
123
false

所以String的修改不是修改原字符串,而是替换字符创指向的引用。

真正的修改原来字符串会有下面的现象

java 复制代码
public class Main {
    public static void main(String[] args) {
        StringBuilder s = new StringBuilder("123");
        StringBuilder b = s;
        System.out.println(b == s);
        s.append("456");
        System.out.println(b);
        System.out.println(b == s);
    }
}

输出

out 复制代码
true
123456
true

验证StringBuilder线程不安全,StringBuffer线程安全

通过对比多线程场景下 StringBuilder 和 StringBuffer 的拼接结果,验证二者的线程安全性:

一个线程负责在末尾添加"1",另一个线程负责在末尾添加"2"。

假如线程安全,那么要么全是1后面接全是2,要么全是2后面接全是1。

如果结果不是这两个,那么线程不安全。

java 复制代码
public class Main {
    public static void main(String[] args) throws InterruptedException {
        int repeatCount = 100000;
        String result1 = "1".repeat(repeatCount) + "2".repeat(repeatCount);
        String result2 = "2".repeat(repeatCount) + "1".repeat(repeatCount);

        StringBuilder stringBuilder = new StringBuilder();
        Thread thread1 = new Thread(() -> {
            stringBuilder.append("1".repeat(repeatCount));
        });
        Thread thread2 = new Thread(() -> {
            stringBuilder.append("2".repeat(repeatCount));
        });
        thread1.start();
        thread2.start();
        thread1.join();
        thread2.join();
        System.out.println(stringBuilder.toString().equals(result1) || stringBuilder.toString().equals(result2));

        StringBuffer stringBuffer = new StringBuffer();
        thread1 = new Thread(() -> {
            stringBuffer.append("1".repeat(repeatCount));
        });
        thread2 = new Thread(() -> {
            stringBuffer.append("2".repeat(repeatCount));
        });
        thread1.start();
        thread2.start();
        thread1.join();
        thread2.join();
        System.out.println(stringBuffer.toString().equals(result1) || stringBuffer.toString().equals(result2));
    }
}

输出

out 复制代码
false
true

如果抛出ArrayIndexOutOfBoundsException,也能证明,ArrayIndexOutOfBoundsException 是 StringBuilder 线程不安全的典型严重表现 ,核心原因是多线程同时操作 StringBuilder 底层的字符数组时,导致数组扩容逻辑混乱,最终触发数组下标越界。

SrringBuffer线程安全的原因,StringBuilder速度快的原因

SrringBuffer对方法加了同步锁,保证了线程安全,但是限制了运行速度。

StringBuilder没有同步锁,所以线程不安全,由于没有锁的限制,执行速度却快。

面试

如果不修改或者修改次数极少,可以用String。

如果需要频繁修改,

多线程下,必须使用StringBuffer来保证线程安全。

单线程下,可以使用StringBuilder比StringBuffer快一些。

相关推荐
用户13051807121516 分钟前
JDBC学习DAY2:从Statement到PreparedStatement
java
蛋蛋的就会顺顺的44 分钟前
hot100——矩阵
java·数据结构·算法·leetcode·力扣
周杰偷奶茶1 小时前
【Java】数组的定义和使用(附管理系统实战案例)
java·开发语言
橙子圆1232 小时前
JUC之集合类不安全
java·开发语言
阿里嘎多学长2 小时前
2026-09-29 GitHub 热点项目精选
开发语言·程序员·github·代码托管
Bruce_Liuxiaowei2 小时前
网页版 DeepSeek “harness desktop“ WebGL 上下文创建失败排查实录
开发语言·javascript·webgl
狗凯之家源码网2 小时前
PHP 用户反馈系统源码深度评测与实战指南
开发语言·php·用户反馈系统
小溪学编程2 小时前
从 C++ 的规范变迁看语言发展
jvm·c++·面试
谢亮_vipxieliang3 小时前
Stream API 不是银弹:常见坑与性能建议
java·开发语言
迅猛龙办公室3 小时前
实现第一个python程序(HelloWorld)
开发语言·python