并发下的ArrayList
情景:两个线程各向同一个ArrayList中添加100 000个元素。
- 可能程序正常结束
- 抛出角标越界异常ArrayIndexOutOfBoundsException
public boolean add(E e) {
// 1 检查容量,如果超出要扩容
ensureCapacityInternal(size + 1);
//2 添加元素
elementData[size++] = e;
return true;
}
列表容量为10,当前已有9个元素 即size = 9;
线程A 进入add()方法,调用 ensureCapacityInternal 进行elementData[] 容量判断;
此时线程B 也进入add()方法,调用ensureCapacityInternal进行容量判断;
线程A 获取size = 9 ,elementData.length =10,无需扩容;
线程B 获取size = 9,elementData.length = 10, 也无需扩容;
线程A 进行赋值elementData[size++] = e 即 elementData[9] = e, size ++ 后 size == 10
线程B进行赋值elementData[size++] = e 即 elementData[10] = e,角标越界
总结:多线程并发操作add(),线程B获取size进行扩容判断时,线程A还没来得及将size加1,所以未触发数组扩容,线程B在赋值时角标越界
- 比实际大小小,线程2覆盖了线程1的值
elementData[size++] = e 赋值操作实际上是两步:
elementData[size] = e
size ++ 自增运算同样是线程不安全的;
假设size=5.若线程A在5位置存放了值valueA,获得size=5,但还没来得及将size加1写入主存。
此时线程B在也在5位置存放了值valueB,也获得size=5,
而后A、B分别将size加1后写入主存,size=6,即两个线程执行两次add()后size只加了1。
解决方案:还没学
https://blog.csdn.net/weixin_35959462/article/details/114061201