2014-12-12 2 views
1

Рассмотрим цикл for для функции, которая берет ссылку ArrayList и добавляет объект к этому массиву ArrayList. Теперь я хотел бы выполнить каждый вызов функции параллельно.Java ArrayList.add() метод потокобезопасный для чисто параллельного добавления?

Является ли метод ArrayList.add() потоком безопасным, если мне не нужна последовательность, в которую добавлены объекты, и никакая функция не читает или не манипулирует никакими элементами ArrayList? Поэтому я хочу только убедиться, что в конце параллельного вызова все объекты добавляются в список.

+0

возможно DUP http://stackoverflow.com/questions/2715983/concurrent-threads-adding-to-arraylist-at-same-time-what-happens –

+0

попробовать 'Collections.synchronizedList (новый ArrayList ())' – rzysia

+0

Вы не ищите мешок тогда? Он может содержать кратность, но порядок не имеет значения. Я не думаю, что Java обеспечивает стандартную реализацию, но это может помочь вам в последующих поисках. – skiwi

ответ

6

Нет, это не поточно-безопасное. Оберните свой список, используя Collections.synchronizedList(), или используйте явную синхронизацию при доступе к списку.

+0

Я хотел бы избежать накладных расходов на синхронизацию, поскольку я не читаю форму ArrayList ... что произойдет, если два потока хотят одновременно добавить в ArrayList? – madison54

+4

Все может случиться: это может сработать, или элементы могут быть потеряны, или вы можете получить исключение, или список может быть в некогерентном состоянии. Сделайте свою программу правильной, а затем посмотрите, достаточно ли она. Если это не так, и если вы докажете, что синхронизированный доступ к списку является проблемой (что маловероятно), тогда и только тогда подумайте о том, как можно оптимизировать код. –

+1

Если OP когда-либо завершает это, он обнаружит, что никакая модель с общим состоянием не может улучшить его производительность. –

0

Для этого вы можете использовать CopyOnWriteArrayList, так как ArrayList не является потокобезопасным.

CopyOnWriteArrayList

EDIT: Я просто хочу котировка Oracle, чтобы показать вам, что это то, что вам нужно:

Нить безопасный вариант ArrayList, в котором все мутационной операции (добавление, set и т. д.) реализуются путем создания новой копии базового массива. Это обычно слишком дорого, но может быть более эффективным, чем альтернативы, когда операции обхода намного превосходят мутации и полезны, когда вы не можете или не хотите синхронизировать обходы, но все же необходимо исключить помехи между параллельными потоками.

+3

«обходные операции значительно превосходят мутации» --- это совсем не похоже на описание ситуации ОП. –

0

Нет, метод add использует ряд свойств уровня класса, которые не имеют контроля над потоками. Вызов add() одновременно в нескольких потоках может вызвать проблемы.

5

ArrayList.add() не является потокобезопасным. Даже если вы не читаете список из других потоков, вы не должны полагаться на это логическое предположение. Вот определение ArrayList.add():

public boolean add(E e) { 
    ensureCapacity(size + 1); 
    elementData[size++] = e; 
    return true; 
} 

В качестве примера проблемы, которые могут возникнуть без синхронизации, атрибут size может быть несовместимым после добавления всех элементов. Если позже вы попытаетесь получить количество элементов, результат может быть неправильным.

+0

Это фактически недооценивает полный потенциал проблем без синхронизации. Даже если код оказался атомарным, он все равно будет разбит без синхронизации. –

+0

@MarkoTopolnik Действительно, это просто простой пример. – manouti

0

Нет, это не нить safe.You есть два варианта:

  1. Либо использовать другую коллекцию: CopyOnWriteArrayList
  2. Использование явной синхронизации во время внесения изменений в список массива в многопоточной среде.
0

Это не поточно-безопасный. В отсутствие синхронизации потоки могут попирать модификацию списка друг друга или, возможно, даже не видят изменений друг друга. В любом случае, это будет испорчено.

Вы должны получить код, начинающийся с Collections.synchronizedList или synchronized statement вокруг вызова для добавления.

Если вы обнаружите, что синхронизация на каждой операции имеет слишком много накладных расходов, следующая альтернатива заключается в том, чтобы дать каждому потоку собственный частный ArrayList, а затем периодически или в конце выгрузить содержимое личных ArrayLists в основной ArrayList.

Смежные вопросы