当多个线程向其中添加元素时,为什么arraylist的大小不正确?

时间:2016-10-26 09:01:28

标签: java arraylist concurrency

为什么当多个线程添加元素时,Arraylist的大小不正确?

threadCount = 100;
List<Object> list = new ArrayList<>();
for (int i = 0; i < threadCount; i++) {
    Thread thread = new Thread(new MyThread(list, countDownLatch));
    thread.start();
}

class MyThread implements Runnable {
    // ......

    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            list.add(new Object());
        }
    }
}

完成此程序后,列表的大小应为10000.实际上,大小可能是9950,9965或其他一些数字。为什么呢?

我知道为什么这个程序可能会引发IndexOutofBoundsException以及为什么会有一些空值,但我只是不明白为什么大小错误。

4 个答案:

答案 0 :(得分:3)

  

我只是不明白为什么尺寸错了?

由于ArrayList不是线程安全的,因此两个线程可以添加相同的索引。所以一个线程会覆盖。

答案 1 :(得分:1)

arraylist不是线程安全的,所以如果对一个arraylist对象进行任何多线程操作,结果是 undefined ,这意味着由于jvm会发生任何事情,包括但不限于错误的大小,异常,内存泄漏,如预期的那样

答案 2 :(得分:0)

很简单, 您正在对对象执行不安全的操作... 所以你无法预测稳定性...... 如果运行足够的次数,list.size()将返回10000时可能有一个实例。 为什么它不会永远回归。??答案是,因为它不是线程安全的。现在考虑添加arraylist的代码

  public boolean add( E element) {
      ensureCapacity(size+1);  // Increments modCount!!
      elementData[index] = element;
     return true;
 }

这里假设当线程10在“ensureCapacity”内部并且它进入睡眠状态时,其他线程(比如线程11)将会到来并且它们(线程10和11)将最终在一个地方插入2个元素。这发生在这里

答案 3 :(得分:0)

你应该参考ArrayList中的源代码。

@Override public boolean add(E object) {
        Object[] a = array;
        int s = size;
        if (s == a.length) {
            Object[] newArray = new Object[s +
                    (s < (MIN_CAPACITY_INCREMENT / 2) ?
                     MIN_CAPACITY_INCREMENT : s >> 1)];
            System.arraycopy(a, 0, newArray, 0, s);
            array = a = newArray;
        }
        a[s] = object;
        size = s + 1;
        modCount++;
        return true;
    }

ArrayList使用System.arraycopy(a, 0, newArray, 0, s)插入元素。如果多线程正在运行,则包含元素的字段数组不是原始元素,并且大小小于预期。