ArrayList线程不安全的情况:
- t1 add时候,size++, 当执行到elementData[size] = e时,时间片用完了,t2 进行add,执行到elementData[size] = e,在数组相同的位置赋值,覆盖了t1的值,回到了t1,size++,t2,也size++,size=2
- size++为多条指令的组合,多线程并发size++时,size会出现并发问题,小于预期结果
- 当数组元素达到临界值-1的时候(临界值为10,15,22,33…),比如到达了size=14,这时候t1执行add,size<=elementData.lengh,未需扩容,准备执行elementData[size] = e,这时t1时间片用完,t2执行add,size=14,因此也未需扩容,并添加了元素,size++,变为了15,这时t1执行赋值操作,elementData[15] = e,此时最大下标为14,因此发生下标越界异常
- 第一个remove线程–size后size为0未写会,再次add,size为2,第一个remove线程将size写会变为0,第二个remove线程执行,发现index(0)>=size(0),报错
// 多线程操作成员变量,不安全
public class ThreadSafe {
// 共享成员变量
List<String> list = new ArrayList<>();
public void m1(int loopNumber) {
for (int i = 0; i < loopNumber; i++) {
m2(list);
m3(list);
}
}
public void m3(List<String> list) {
list.remove(0);
}
public void m2(List<String> list) {
list.add("1");
}
public static void main(String[] args) {
ThreadSafe threadSafe = new ThreadSafe();
for (int i = 0; i < 2; i++) {
new Thread(()->{
threadSafe.m1(200);
},"t"+(i+1)).start();
}
}
}
class ArrayList {
public boolean add(E e) {
// 该方法会进行扩容,当数组元素填满时,原数组的长度为增长为原来的1.5倍
ensureCapacityInternal(size + 1); // Increments modCount!!
elementData[size++] = e;
return true;
}
public E remove(int index) {
rangeCheck(index);
modCount++;
E oldValue = elementData(index);
int numMoved = size - index - 1;
if (numMoved > 0)
System.arraycopy(elementData, index+1, elementData, index,
numMoved);
elementData[--size] = null; // clear to let GC do its work
return oldValue;
}
}
// 改进:将list移进m1()方法内成为局部变量
// 子类继承父类并重写m3()方法
class ThreadSubSafe extends ThreadSafe {
@Override
public void m3(List<String> list) {
new Thread(() -> {
list.remove(0);
}).start();
}
}