先看看多个线程同时对一个ArrayList进行add的操作
public static void main(String[] args) throws InterruptedException {
ArrayList<Integer> list = new ArrayList<>();
Thread thread0 = new Thread(() -> {
for (int i = 0; i < 100; i++) {
list.add(i);
}
});
Thread thread1 = new Thread(() -> {
for (int i = 0; i < 100; i++) {
list.add(i);
}
});
thread0.start();
thread1.start();
Thread.sleep(100);
System.out.println(list.size());
}
结果:
Exception in thread "Thread-0" java.lang.ArrayIndexOutOfBoundsException: 10
at java.util.ArrayList.add(ArrayList.java:459)
at com.ldy.demoz.delete.Test.lambda$main$0(Test.java:21)
at java.lang.Thread.run(Thread.java:745)
101
看一下报错行源码:
原因
- 列表大小为9,即size=9
- 线程0开始进入add方法,这时它获取到size的值为9,调用ensureCapacityInternal方法进行容量判断。
- 线程1此时也进入add方法,它获取到size的值也为9,也开始调用ensureCapacityInternal方法。
- 线程0发现需求大小为10,而elementData的大小就为10,可以容纳。于是它不再扩容,返回。
- 线程1也发现需求大小为10,也可以容纳,返回。
- 线程0开始进行设置值操作, elementData[size++] = e 操作。此时size变为10。
- 线程1也开始进行设置值操作,它尝试设置elementData[10] = e,而elementData没有进行过扩容,它的下标最大为9。于是此时会报出一个数组越界的异常ArrayIndexOutOfBoundsException.
(具体源码可参考ArrayList源码分析)
一句话来说就是ArrayList的操作不是原子性的。
网友评论