Почему размер arraylist не правильный, когда несколько потоков добавляют элементы в него?

java arraylist concurrency

730 просмотра

4 ответа

59 Репутация автора

Почему размер 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и почему в ней есть некоторые нули, но я просто не понимаю, почему размер неправильный.

Автор: fei_hsueh Источник Размещён: 26.10.2016 09:01

Ответы (4)


3 плюса

12202 Репутация автора

Я просто не понимаю, почему размер неправильный?

Поскольку ArrayList не является потокобезопасным, два потока могут добавляться с одинаковым индексом. Так что один поток перезаписывает.

Автор: Azodious Размещён: 26.10.2016 09:04

0 плюса

79 Репутация автора

Это просто, вы выполняете небезопасную операцию над объектом ... Таким образом, вы не можете предсказать стабильность ... Если вы запустите достаточно раз, может быть один экземпляр, когда list.size () вернет 10000. Почему это не так? возвращаться всегда. Ответ, потому что это не потокобезопасно. Теперь рассмотрим код добавления в arraylist

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

Предположим здесь, что когда поток 10 находится внутри «sureCapacity» и переходит в спящий режим, тогда придет другой поток (скажем, поток 11), и они (поток 10 и 11) в конечном итоге вставят 2 элемента в одном месте. Это происходит здесь

Автор: RAHUL ROY Размещён: 26.10.2016 09:17

1 плюс

99 Репутация автора

arraylist не является поточно-ориентированным, поэтому если какая-либо многопотоковая операция над одним объектом arraylist, результат не определен,, что означает, что все может произойти из-за jvm, включая, но не ограничиваясь, неправильный размер, исключение, утечку памяти, как и ожидалось

Автор: dexter Размещён: 26.10.2016 09:32

0 плюса

1 Репутация автора

Вы должны обратиться к исходному коду в 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)для вставки элемента. Если запущено несколько потоков, массив полей, содержащий элементы, не является исходным, и его размер меньше ожидаемого.

Автор: McJudy Размещён: 28.02.2017 03:18
Вопросы из категории :
32x32