简单的回答:因为相对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的时候,在内存中就不同步啦