1 ArrayList是线程安全的吗?
否
2 多线程情况下往ArrayList里面添加元素,会导致什么问题?
源码分析
public boolean add(E e) {
//检测长度并扩容
ensureCapacityInternal(size + 1); // Increments modCount!!
//元素放到 size位置 并使size=size+1
elementData[size++] = e;
return true;
}
private void ensureCapacityInternal(int minCapacity) {
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
//数组为空,给个默认值10
minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
}
ensureExplicitCapacity(minCapacity);
}
private void ensureExplicitCapacity {
modCount++;
// overflow-conscious code
if (minCapacity - elementData.length > 0)
grow(minCapacity);
}
根据上面执行流程,其实我们很容器发现问题的所在,其实就是最后这一行代码elementData[size++] = e;导致。添加一个元素我们可以理解为:
- 在 elementData[Size] 的位置存放此元素;
- 增大 Size 的值。
运行的过程如下所示:
1、线程1 赋值 element[1] = 1; 随后因为时间片用完而中断; 此时size = 1
2、线程2 赋值 element[1] = 2; 随后因为时间片用完中断; 此时size = 1
此处导致了之前所说的一个问题(有的线程没有输出); 因为后续的线程将前面的线程的值覆盖了,导致了值被覆盖问题
3、线程1 自增 size++; (size=2)
4、线程2 自增 size++; (size=3)
此处导致了某些节点值为null的问题。 因为原size=1, 但是因为线程1与线程2都将值赋值给了element[1],导致了element[2]内没有值,被跳过了,
指针index指向了3.所以,导致了某些情况下值为null的情况,可能在获取它进行计算的时候报了空指针异常。
导致了数组越界问题前提条件: 当前size=1 数组长度为3 (下标有 0,1,2)
1、线程1 判断数组是否越界.因为size=2 长度为3,没有越界.将进行赋值操作.但是因为时间片问题导致了中断.
2、线程2 判断数组是否越界.因为size=2 长度为3,没有越界.将进行赋值操作.但是因为时间片问题导致了中断.
3、线程1 重新获取到主动权.上文判断了长度刚刚好够用.进行赋值操作element[size]=1,并且size++ 此时size=3
4、线程2 因为上文判断了数组没有越界.所以进行赋值操作.但是此时的size=3了.再执行element[3]=2. 导致了数组越界了(因为本身数组长度是3,最大索引只能是2)