Параллельные потоки, добавляющие к ArrayList в то же время - что происходит?

У нас есть несколько вызовов потоков add(obj) на ArrayList.

Моя теория - это когда add назван одновременно двумя потоками, это, только один из двух добавляемых объектов действительно добавляется к ArrayList. Действительно ли это вероятно?

Если так, как Вы обходите это? Используйте синхронизируемый набор как Vector?

51
задан Marcus Leon 26 April 2010 в 07:46
поделиться

7 ответов

Не существует гарантированного поведения того, что происходит, когда добавление вызывается одновременно двумя потоками в ArrayList. Однако, по моему опыту, оба объекта были добавлены нормально. Большинство проблем безопасности потоков, связанных со списками, связаны с итерацией при добавлении / удалении. Несмотря на это, я настоятельно рекомендую не использовать ванильный ArrayList с несколькими потоками и одновременным доступом.

Вектор раньше был стандартом для параллельных списков, но теперь стандартом является использование синхронизированного списка Коллекции .

Также я настоятельно рекомендую Java Concurrency in Practice от Goetz et al, если вы собираетесь тратить какое-то время на работу с потоками в Java. В книге этот вопрос освещен гораздо лучше.

52
ответ дан 7 November 2019 в 10:12
поделиться

Вы также можете получить null , ArrayOutOfBoundsException или что-то еще, оставшееся до реализации. HashMap уходит в бесконечный цикл в производственных системах. Вам действительно не нужно знать, что может пойти не так, просто не делайте этого.

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

9
ответ дан 7 November 2019 в 10:12
поделиться

вы можете использовать List l = Collections.synchronizedList (new ArrayList ()); , если вам нужна поточно-безопасная версия arrayList.

3
ответ дан 7 November 2019 в 10:12
поделиться

http://java.sun.com/j2se/1.4.2/docs/api/java/util/ArrayList.html

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

Поскольку внутренней синхронизации нет, то, что вы теоретизируете, неправдоподобно.

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

0
ответ дан 7 November 2019 в 10:12
поделиться

java.util.concurrent имеет список потоковобезопасных массивов. Стандартный список ArrayList не является потокобезопасным, и поведение при одновременном обновлении нескольких потоков не определено. Также может быть странное поведение с несколькими читателями, когда один или несколько потоков пишут одновременно.

1
ответ дан 7 November 2019 в 10:12
поделиться

Произойдет любое количество вещей. Вы можете правильно добавить оба объекта. Вы могли добавить только один из объектов. Вы можете получить исключение ArrayIndexOutOfBounds, потому что размер базового массива не был скорректирован должным образом. Или могут произойти другие вещи. Достаточно сказать, что вы не можете полагаться на какое-либо поведение.

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

16
ответ дан 7 November 2019 в 10:12
поделиться

Поведение, вероятно, не определено, поскольку ArrayList не является потокобезопасным. Если вы измените список, когда Iterator взаимодействует с ним, вы получите ConcurrentModificationException. Вы можете обернуть ArrayList с помощью Collection.synchronizedList или использовать потокобезопасную коллекцию (их много) или просто поместить вызовы добавления в синхронизированный блок.

2
ответ дан 7 November 2019 в 10:12
поделиться
Другие вопросы по тегам:

Похожие вопросы: