https://blog.csdn.net/weixin_45668482/article/details/117396603
在单线程开发环境中,我们经常使用ArrayList作容器来存储我们的数据,但它不是线程安全的,在多线程环境中使用它可能会出现意想不到的结果。
我们可以从一段代码了解并发环境下使用ArrayList的情况:
public class ConcurrentArrayList {
public static void main(String[] args) throws InterruptedException {
List<Integer> list = new ArrayList<>();
Runnable runnable = () -> {
for (int i = 0; i < 10000; i++) {
list.add(i);
}
};
for (int i = 0; i < 2; i++) {
new Thread(runnable).start();
}
Thread.sleep(500);
System.out.println(list.size());
}
}
代码中循环创建了两个线程,这两个线程都执行10000次数组的添加操作,理论上最后输出的结果应该为20000,但经过多次尝试,最后只出现了两种结果:
Exception in thread "Thread-0" java.lang.ArrayIndexOutOfBoundsException: 10
at java.util.ArrayList.add(ArrayList.java:463)
at ConcurrentArrayList.lambda$main$0(ConcurrentArrayList.java:14)
at java.lang.Thread.run(Thread.java:748)
10007
16093
虽然仍有可能得到20000的结果,但概率非常低。我们要从ArrayList的源码中去分析为什么会出现这种结果。
ArrayList数组默认初始化大小:
// 默认初始大小
private static final int DEFAULT_CAPACITY = 10;
...
// 数组size
private int size;
ArrayList的add方法:
public boolean add(E e) {
//确定集合的大小是否足够,如果不够则会进行扩容
ensureCapacityInternal(size + 1); // Increments modCount!!
elementData[size++] = e;
return true;
}
以上面错误1:ArrayIndexOutOfBoundsException: 10为例,出现错误的步骤如下: