为什么说StringBuilder线程不安全?

简单的回答:因为相对StringBuffer,StringBuilder没有在方法上使用 synchronized 关键字。例如

StringBuffer :
    @Override
    public synchronized StringBuffer append(String str) {
        toStringCache = null;  //这行是做什么的,有待研究
        super.append(str);
        return this;
    }
StringBuilder :
@Override
public StringBuilder append(String str) {
    super.append(str);
    return this;
}

 

再进入 StringBuilder 的 super.append(str);看一看

 

public AbstractStringBuilder append(String str) {
        if (str == null)
            return appendNull();
        int len = str.length(); //获得在后缀增加字符串的长度
        ensureCapacityInternal(count + len);// 扩容,如果 扩容为 (当前长度*2)+2 还小于所需要的最小长度空间,那么久 扩容为最小长度空间。当前值得两倍+2 int newCapacity = (value.length << 1) + 2;   
        str.getChars(0, len, value, count);//getChars(int srcBegin, int srcEnd, char[] dst, int dstBegin) 将str 赋值到 value 从count开始
        count += len;//重点就是这一行代码,他不是原子操作,多线程的时候会导致长度count不同步。这样就线程不安全了
        return this;
    }

 

 

下面是demo程序运行结果

public class StringBuilderDemo2 {

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

                }
            }
            ).start();
        }

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

}

 

如果线程安全,这里结果应该是显示100000的。如果使用StringBuffer就可以避免这个问题

所以,主要是因为  count += len;这一行代码不是原子操作,

conut = count +len;多个线程访问count的时候,在内存中就不同步啦

posted @ 2019-11-19 14:20  wullll  阅读(737)  评论(0编辑  收藏  举报