例子:
多线程操作StringBuilder对象:
public class StringBuilderDemo{
public static void main(String[] args) throws InterruptedException{
StringBuilder sBuilder = new StringBuilder();
for(int i=0;i<10;i++){
new Thread(new Runnable(){
@Override
public void run(){
for(int j=0;j<1000;j++){
sBuilder.append("a");
}
}
}).start();
}
Thread.sleep(100);
System.out.println(sBuilder.length());
}
}
运行结果:7346
问题1:为什么不是10000(中心思想:覆盖)
StringBuilder的两个成员变量:
//存储字符串的具体内容
char[] value;
//已经使用的字符数组的数量
int count;
StringBuilder的append()方法调用父类“AbstractStringBuilder”的append()方法:
public AbstractStringBuilder append(String str){
if(str==null){
return appendNull();
}
int len = str.length();
//验证原数组是否需要扩容
ensureCapacityInternal(count + len);
//拼接元素
str.getChars(0,len,value,count);
//记录拼接后的元素个数(注意是个数)
count += len;
return this;
}
找到count += len,假设count为10,len值为1,两个线程同时执行到这里,拿到的count值都为10,结果两个线程执行完后的count值为11,而不是12,而且getChars方法被同时执行(可理解为:拼接第x个元素时,这几个线程同时运行导致覆盖,都往一个地方同时放一样的东西可不就变成一个了嘛)。
问题2:抛异常:ArrayIndexOutOfBoundsException(中心思想:一个数组满了,你非得再加一个元素,人家还没有位置给你,可不得异常嘛)
条件1:
public AbstractStringBuilder append(String str){
if(str==null){
return appendNull();
}
int len = str.length();
//验证原数组是否需要扩容
ensureCapacityInternal(count + len);
//拼接元素
str.getChars(0,len,value,count);
//记录拼接后的元素个数(注意是个数)
count += len;
return this;
条件2:
//建立一个有内容的初始化数组
String Str1 = new String("www.runoob.com");
// 下标:0 1 2 3 4
char[] Str2 = new char[5];
//到此 Str2的前三个元素:0——r 1——u 2——n 3——o 4——没有
Str1.getChars(4,8,Str2,0);
//两个线程 分别 拿出A 和 B 放进Str2,分别放在 下标4和5。
"ABCD".getChars(0,1,Str2,4);//线程1
"ABCD".getChars(1,2,Str2,5);//线程2
//报错(人家就剩一个位置是4 线程1先使用了,线程2无处放,又不让扩容,故报错)
两个线程都走完了条件1的ensureCapacityInternal方法,都说不需要扩容,接着走getChars方法,唉呀妈呀:线程2这个时候掉链子了,不走了,线程1接着走,老1走完 把他手里的元素放在了最后一个位置,数组满了,然后登记一下count为5,这个时候老2醒了,但是已经不能再回去进行扩容数组了啊,因为刚才都说了不需要扩容,这咋整 ?数组满了呀,又不能在扩容,那就抛出异常呗!!!(例如条件2)