StringBuilder和StringBuffer的区别

简介: StringBuilder和StringBuffer的区别

    StringBuilder和StringBuffer的用法是一致的,平常我们最多用到的方法就是append()拼接字符串和reverse()翻转字符串等等。二者看起来方法是一样的,确实也是这样,其实它俩唯一的不同在于StringBuilder不是线程安全的,而StringBuffer则是线程安全的。


证明如下

验证StriingBuilder

我们分别用两个线程对同一StringBuilder对象追加不同的字符,查看结果

public static void main(String[] args) throws InterruptedException {
        StringBuilder builder = new StringBuilder();
        StringBuffer buffer = new StringBuffer();
        Thread t1 = new Thread(new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i < 1000; i++) {
                    builder.append("A");
                }
            }
        });
        Thread t2 = new Thread(new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i < 1000; i++) {
                    builder.append("B");
                }
            }
        });
        t1.start();
        t2.start();
        t1.join();
        t2.join();
        System.out.println(builder.toString());
    }

结果:

       我们发现,线程1(追加字符‘a’)运行得好好的,突然线程2(追加字符‘b’)也加了进来,两个线程轮流对StringBuilder对象进行操作

    此外,还发生了下标越界的报错,可能是因为两个线程在争夺资源的时候发生的错误,毕竟StringBuilder的底层其实是一个char数组,线程 A 想要在位置 i 插入字符,而线程 B 想要在相同的位置 i 插入不同的字符。这将导致一个或者两个操作执行失败或者得到错误结果。所以运行结果中不只有AB两种字符,还有一个类似乱码的字符

结论:StringBuilder不是线程安全的

验证StringBuffer

验证方法和上面一直,我们分别用两个线程对同一StringBuffer对象追加不同的字符,查看结果

public static void main(String[] args) throws InterruptedException {
        StringBuilder builder = new StringBuilder();
        StringBuffer buffer = new StringBuffer();
        Thread t1 = new Thread(new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i < 1000; i++) {
                    buffer.append("A");
                }
            }
        });
        Thread t2 = new Thread(new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i < 1000; i++) {
                    buffer.append("B");
                }
            }
        });
        t1.start();
        t2.start();
        t1.join();
        t2.join();
        System.out.println(buffer.toString());
    }

结果:

       我们发现,尽管是两个线程,但是并没有因为抢占公共资源(同一个StringBuffer对象)而交替执行,而是很丝滑快速的执行完成,更没有报错。

结论:StringBuffer是线程安全的

总结

两个线程同时操作同一个 StringBuilder 对象,如果没有采取合适的同步机制,那么就会出现下标越界的错误。

在多线程环境下,由于线程调度是不可控的,两个线程可能同时访问同一个 StringBuilder 对象,并且同时调用 append() 或 insert() 等方法进行修改操作。由于 StringBuilder 不是线程安全的类,在并发访问时可能会出现以下问题:


1. 竞态条件:如果两个线程在同一时间进行 append() 或 insert() 操作,则可能会导致竞态条件。例如,线程 A 想要在位置 i 插入字符,而线程 B 想要在相同的位置 i 插入不同的字符。这将导致一个或者两个操作执行失败或者得到错误结果。


2. 内存可见性:如果两个线程分别持有 StringBuilder 的不同实例,并且每个实例都缓存了修改后的值,则另一个线程可能无法看到这些更改,因此应该使用 volatile 关键字保证内存可见性。


综上所述,为了避免 StringBuilder 下标越界错误和其他多线程问题,需要采取合适的同步机制来保证对 StringBuilder 的访问是互斥、有序和可见的。例如可以使用 synchronized 来锁住StringBuilder对象,或者使用 ConcurrentLinkedQueue<StringBuilder> 之类的线程安全容器来避免竞争条件。

       因此,当我们今后使用的时候,需要注意场景。内容拼接在一起的话,需要使用StringBuffer,而一般单线程的情况下可以使用StringBuilder。

相关文章
|
6天前
|
存储 缓存 Java
JavaSE 字符串String及相关API StringBuilder StringJoiner 底层原理 详解
JavaSE 字符串String及相关API StringBuilder StringJoiner 底层原理 详解
12 2
|
23天前
|
安全 Java API
JavaSE——常用API进阶一(3/3)-StringBuilder(构造器、拼接内容、反转操作、其他操作),StringBuffer,StringJoiner
JavaSE——常用API进阶一(3/3)-StringBuilder(构造器、拼接内容、反转操作、其他操作),StringBuffer,StringJoiner
21 1
|
26天前
|
安全 Java 测试技术
滚雪球学Java(50):理解Java中String、StringBuilder和StringBuffer的区别与选择
【6月更文挑战第4天】🏆本文收录于「滚雪球学Java」专栏,专业攻坚指数级提升,希望能够助你一臂之力,帮你早日登顶实现财富自由🚀;同时,欢迎大家关注&&收藏&&订阅!持续更新中,up!up!up!!
17 0
滚雪球学Java(50):理解Java中String、StringBuilder和StringBuffer的区别与选择
|
10天前
|
安全
StringBuffer,StringBuilder的区别及其源码分析
StringBuffer,StringBuilder的区别及其源码分析
|
1月前
|
存储 安全 Java
【JAVA学习之路 | 提高篇】StringBuffer与StringBuilder
【JAVA学习之路 | 提高篇】StringBuffer与StringBuilder
|
18天前
|
Java
guava Splitter 与java 内置的string的split 方法的区别
guava Splitter 与java 内置的string的split 方法的区别
14 0
|
1月前
|
存储 安全 Java
javaSE-String,StringBuffer和StringBuilder
javaSE-String,StringBuffer和StringBuilder
25 0
|
7天前
|
Java UED
Java中String强转int:一种常见的错误和解决方法
在Java中将非数字字符串转换为整数会导致`NumberFormatException`。要解决这个问题,可以使用`try-catch`捕获异常,正则表达式验证数字格式,或利用异常信息提供错误提示。例如,`Integer.parseInt()`会因遇到非数字字符如`&quot;123abc&quot;`而抛出异常,但通过异常处理或正则`\\d+`可确保安全转换。记得在编程时避免直接强转,以防止程序异常中断。
|
2天前
|
安全 Java
Java基础之StringBuffer
Java中的`StringBuffer`是线程安全的可变字符串,适用于多线程环境,其方法同步导致较慢。`StringBuilder`在Java 5引入,非线程安全但更快,适合单线程操作。两者均提供append、insert、delete等方法。在不需要线程安全时,选择`StringBuilder`以提升效率。
8 1
|
6天前
|
Java 数据处理 Apache
探讨Java中判断String类型为空和null的方法
探讨Java中判断String类型为空和null的方法
11 1