ArrayList非线程安全的原因

【ArrayList的实现】

ArrayList的实现主要有: 一个Object的elementData的数组保存所有的元素;一个size变量保存当前数组中已经添加了多少元素。

    /**
     * The array buffer into which the elements of the ArrayList are stored.
     * The capacity of the ArrayList is the length of this array buffer. Any
     * empty ArrayList with elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA
     * will be expanded to DEFAULT_CAPACITY when the first element is added.
     */
    transient Object[] elementData; // non-private to simplify nested class access

    /**
     * The size of the ArrayList (the number of elements it contains).
     *
     * @serial
     */
    private int size;

【add操作的源码】

add操作大概分为两步:一、判断列表的capacity容量是否足够,是否需要扩容;二、将元素放在列表的元素数组里

线程不安全的隐患(1):

假设列表当前大小为8,即size=8

线程A开始进入add方法,这是它获得到size的值为8,调用ensureCapacityInternal方法进行容量判断。

线程B此时也进入add方法,它获取到的size值也为8,也开始调用ensureCapacityInternal方法。

线程A发现需求大小为8+1=9,而elementData的大小刚好为9,可以容纳。于是它不再扩容,返回。

线程B也发现需求大小为9,也可以容纳,返回。

线程A开始进行设置值操作,执行elementData[size++]=e后,size变为9。

线程B也开始进行设置值操作,执行elementData[size++]即elementData[9]=e。此时会报一个数组越界的异常ArrayIndexOutOfBoundsException

线程不安全的隐患(2):

另外elementData[size++]=e设置值的操作也会导致线程不安全。因为这步操作不是一个原子操作,它由以下两步构成:

1、elementData[size]=e;

2、size = size+1;

假设elementData当前size大小为0

线程A添加一个元素“A”,将“A”放在elementData下标为0的位置上。

接着线程B刚好也要添加一个元素"B",且走到了第一步操作。此时线程B获取的size值依然是0,于是线程B将“B”也放在了elementData下标为0的位置上。

然后,线程A将size的值增加为1;线程B将size的值增加为2。

这样线程A、B执行完成后,elementData的期待结果为:size为2,elementData[0]="A",elementData[1]="B"。

而实际情况是:size为2,elementData[0]="B",elementData[1]=null。


    /**
     * Appends the specified element to the end of this list.
     *
     * @param e element to be appended to this list
     * @return <tt>true</tt> (as specified by {@link Collection#add})
     */
    public boolean add(E e) {
        ensureCapacityInternal(size + 1);  // Increments modCount!!
        elementData[size++] = e;
        return true;
    }



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

        ensureExplicitCapacity(minCapacity);
    }

    private void ensureExplicitCapacity(int minCapacity) {
        modCount++;

        // overflow-conscious code
        if (minCapacity - elementData.length > 0)
            grow(minCapacity);
    }

猜你喜欢

转载自blog.csdn.net/sjmz30071360/article/details/89453947