ArrayList从源码上看其线程安全问题(jdk1.8)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/about4years/article/details/69650763

ArrayList是线程不安全的。我们来看他的add方法:

public boolean add(E e) {
    ensureCapacityInternal(size + 1);  // 传入size+1
    elementData[size++] = e;  //赋值,size++
    return true;
}

首先调用ensureCapacityInternal方法,顾名思义:首先要确保容量,不然怎么add。我们看这个方法:

private void ensureCapacityInternal(int minCapacity) {
    if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
        minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
    }
    ensureExplicitCapacity(minCapacity);
}

第一个if语句是用于初次add元素的扩容的,将会扩容到10.(这一部分可以看上一篇)

看接下来的方法:

private void ensureExplicitCapacity(int minCapacity) {
    modCount++;  //fast-fail
    //如果目前的容量足够的话,是不会扩容的
    if (minCapacity - elementData.length > 0)
        //如果传入的size+1 > 目前的数组长度了,那么进行扩容操作
        grow(minCapacity);
}

grow方法,就不细述了,是通过数组复制的办法进行的,扩了1.5倍。回到最初的add方法,接下来执行的句子:

elementData[size++] = e;

拆成2句:

elementData[size] = e;  //1
size++;  //2

这里就可以看出端倪了:假定2个线程A,B同时add一个元素,A执行到第一句,此时cpu给了B,此时size并没有加1,所以线程B所add的值就覆盖了线程A所add的,接下来size++,加了2次,elementData[size+1]就变成了null。

还有一种情况:会直接抛出异常,我们假定一个场景,此时arraylist中数组容量为4,size为3,就是还有一个空位置,此时线程A,B同时add一个元素,A执行完ensureCapacityInternal(size + 1),因为还没有到需要扩容的条件,是不会扩容的,此时容量还是4,接着B拿到CPU,也执行ensureCapacityInternal(size + 1),当然也不会执行扩容,接着继续执行,elementData[size] = e; size++; 接着cpu给了A,异常发生,此时size=4了,容量也=4,然而线程A已经执行过ensureCapacityInternal这个方法了,直接调用elementData[size] = e也就是elementData[4] = e,那么肯定就抛出异常了(数组越界)。

写一个最简单的例子:

public static void main(String[] args) throws InterruptedException {
        List<Integer> list = new ArrayList<>();


        new Thread(()->{
            for (int i=0; i<1000; i++) {
                list.add(i);
            }
        }).start();

        new Thread(()->{
            for (int i=0; i<1000; i++) {
                list.add(i);
            }
        }).start();
        TimeUnit.SECONDS.sleep(2);
        System.out.println(list.size());
        list.forEach(o-> System.out.print(o+" "));
    }

输出结果可能直接抛异常,可能输出的size<2000,当然也有可能输出正常。

 





 


 

猜你喜欢

转载自blog.csdn.net/about4years/article/details/69650763