Java 看完快去给面试官说说为啥StringBuilder线程不安全

从 StringBuilder的源码维度去解读为啥导致线程不安全 。

先回顾一下我曾写过的类似 线程不安全的文章:

面试官问 : ArrayList 不是线程安全的,为什么 ?(看完这篇,以后反问面试官)

面试官问 : SimpleDateFormat 不是线程安全的,你有了解过吗?

如果有去看过,你的心,是很明亮的。 
(这个线程不安全,肯定又是有哪个公共变量在搞事。)

好的 ,事不宜迟,我们开始。

StringBuilder 线程不安全,直接锁定 append方法 。

源码:
 

(好了,结束了。 就是这些公共变量搞事情。)

哪里导致不安全?

看到这行代码没 ?

非原子操作   count += len;

简单举个最简单的例子,去看看这个非原子操作的线程并发的场景。

AB两个线程当前count (公共全局变量) 都是 100 , 而 都传入了 str = ‘x’  ,也就是 int len = str.length();  len为1.

这时候 都去执行   count += len;   

AB 两个线程 拿到count 都是 100, 然后共同执行 +1,  然后共同拿到结果 count=101  。

这时候,已经出现问题了 。 正常应该是后者拿到count为102  .

所以说,如果线程并发多,不只是AB,而是ABCDEFG, 那 count的值, 都不准成啥样了。。。

那么继续看这个    count += len;     的上面一行  

str.getChars(0, len, value, count);

public void getChars(int srcBegin, int srcEnd, char dst[], int dstBegin) {
    if (srcBegin < 0) {
        throw new StringIndexOutOfBoundsException(srcBegin);
    }
    if (srcEnd > value.length) {
        throw new StringIndexOutOfBoundsException(srcEnd);
    }
    if (srcBegin > srcEnd) {
        throw new StringIndexOutOfBoundsException(srcEnd - srcBegin);
    }
    System.arraycopy(value, srcBegin, dst, dstBegin, srcEnd - srcBegin);
}

char dst[]  是 传入的 value[]  

而dstBegin 就是传入count 

简单解释:

正常一个个元素新增,  value[]   长度到 9, 那么 count就是10 ,代表dstBegin从 第10个位置新增元素(有序正常进行) 。

想想一种情景。

就是 比如 这个数组当前最大容量是10 ,然后 即将新增元素后本身得到的count是11, 11-10>0

是需要扩容的,

这样扩容之后,这个函数的意义就很对。(保证正常扩容,到了临界点就扩容,这样后面的线程新增元素就包妥了)

但是! 但是!但是! 

如果 并发出现了! 



也就是 说 后面的B线程本身拿到的count值 是A线程执行完+1的才对!

但是呢,因为并发,AB 线程拿到的count值是一样的,都没触发扩容,相当

于 ensureCapacityInternal这个函数, 都绕过去了, 没扩容 。

所以B线程执行到      str.getChars(0, len, value, count);  

这时候就会出现 dst    传入的 value[]    和 dstBegin   传入的count  是一样的。。。

就是说 数组容量塞满了(比如是10),然后你告诉我 下一个新增元素的位置 也是10, 那于是乎,当然就抛出异常 数组越界 ArrayIndexOutOfBoundsException 咯。

好了,该篇就到这。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小目标青年

对你有帮助的话,谢谢你的打赏。

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值