Stringbuilder和StringBuffer线程安全的区别

StringBuilder是线程不安全的,而StringBufffer是线程安全的为什么呢?

首先我们要明白的是StringBuilder和StringBuffer的内部实现跟String类一样,都是通过访问一个char数组存储字符串的,不同时的是String类里面的char数组都是final修饰的,是不可变的,而StringBuilder和StringBuffer的char数组是可变的。

StringBuilder和StringBuffer都继承了AbstractStringBuilder

一.StringBuilder

我先先看一段代码

public class StringBuilderDemo {

    public static void main(String[] args) throws InterruptedException {
        StringBuilder stringBuilder = new StringBuilder();
        for (int i = 0; i < 10; i++){
            new Thread(new Runnable() {
                @Override
                public void run() {
                    for (int j = 0; j < 1000; j++){
                        stringBuilder.append("a");
                    }
                }
            }).start();
        }

        Thread.sleep(100);
        System.out.println(stringBuilder.length());
    }

}

我们能看到这段代码创建了10个线程,每个线程循环1000次往StringBuilder对象里面append字符。正常情况下代码应该输出10000,但是实际运行会输出什么呢?

image-20230421113726889

ArrayIndexOutOfBoundsException异常(异常不是必现)。

image-20230421114625389

1.解答

我们先看一下StringBuilder的两个成员变量(这两个成员变量实际上是定义在AbstractStringBuilder里面的,StringBuilder和StringBuffer都继承了AbstractStringBuilder

image-20230421113918143

1.StringBuilder的append()方法:

@Override
public StringBuilder append(String str) {
    super.append(str); 
    return this;
}

这里面又去调用了父类AbstractStringBuiler的append()方法

image-20230421114129422

我们先直接看int spaceNeeded=cout+appendedLength;这并不是一个原子操作,假设cout为5,appendedLength为1,两个线程同时到了这一行,同时拿到的cout是5,但是第一个线程执行完之后是spaceNeeded是6,第二个线程得到的结果也是6并不是我们所想的7.这就是为什么得到的结果比1000小了。

2.为什么会抛出ArrayIndexOutBoundsException异常。

我们可以看一下ensureCapacityInternal()方法是检查StringBuilder对象的原char数组的容量能不能盛下新的字符串,如果盛不下就调用对char数组进行扩容【原来的2倍+2】。

image-20230421114826889

image-20230421114919021

Arrys.copyof()方法

image-20230421155536810

getChars()方法:

public void getChars(int srcBegin, int srcEnd, char dst[], int dstBegin) {
    //中间省略了一些检查
    ...   
    System.arraycopy(value, srcBegin, dst, dstBegin, srcEnd - srcBegin);
    }

image-20230421155635919

image-20230421155648737

二:StringBuffer

image-20230421155722838

加了synchronized

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值