Java - Потокобезопасность конструкторов ArrayList

Я смотрю на эту часть кода. Этот конструктор делегирует к собственному методу "System.arraycopy"

Действительно ли это ориентировано на многопотоковое исполнение? И этим я подразумеваю, что это может когда-либо бросать ConcurrentModificationException?

public Collection<Object> getConnections(Collection<Object> someCollection) {
    return new ArrayList<Object>(someCollection);
}

Это имеет какое-либо значение, если скопированным набором является ThreadSafe, например, CopyOnWriteArrayList?

public Collection<Object> getConnections(CopyOnWriteArrayList<Object> someCollection) {
    return new ArrayList<Object>(someCollection);
}

Править: Я знаю тот ThreadSafe! = ConcurrentModificationException. Я пытаюсь взять снимок данных в моменте времени. Поэтому, если другой Поток пишет в someCollection на полпути через копию, я не забочусь, имеет ли результат новый объект или нет. Я просто не хочу, чтобы это бросило ConcurrentModificationException или хуже

9
задан andy boot 21 April 2010 в 17:27
поделиться

4 ответа

Ваш вопрос заключается в том, можете ли вы безопасно получить снимок коллекции, которая может подвергаться одновременной модификации другим потоком, используя new ArrayList ( thatCollection) . Ответ таков: пока thatCollection сам по себе является потокобезопасным, да. Итак, если это CopyOnWriteArrayList , synchronizedList или Vector , если он не является поточно-ориентированным, например, если это еще один ArrayList , вы » не в порядке. (То, что произойдет, может быть хуже, чем исключение ConcurrentModificationException .)

Причина в том, что конструктор ArrayList выполняет только один атомарный вызов другой коллекции - ее ] toArray метод. Таким образом, он, по сути, пользуется всеми гарантиями безопасности потоков, которые имеет сам метод. Не всегда это реализовывалось так, но теперь по этой причине. Мы делаем то же самое в Guava с ImmutableList.copyOf .

5
ответ дан 4 December 2019 в 11:40
поделиться

Этот конструктор делегирует собственный метод System.arraycopy

На самом деле он вызывает toArray () в someCollection . В конечном итоге это вызовет System.arraycopy , если someCollection является ArrayList . Для других типов коллекций массив будет создан другими способами.

Это потокобезопасно?

Нет.

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

Если это ArrayList , он не вызовет ConcurrentModificationException ... , но это действительно не делайте его поточно-ориентированным !!

Например, если другой поток вызывает set (obj, pos) на someCollection , в то время как ваш поток вызывает этот конструктор, то содержимое вашего вновь созданного ArrayList непредсказуемы.

7
ответ дан 4 December 2019 в 11:40
поделиться

ConcurrentModificationException - не единственный признак того, что что-то небезопасно для потоков. Если, например, в методе № 1 someCollection также является ArrayList, у вас никогда не будет исключения ConcurrentModificationException (см. Код). Однако целостность данных находится под угрозой - если исходный ArrayList изменяется во время его копирования, только некоторые изменения могут быть отражены в копии (и не обязательно самые старые изменения!).

Другими словами, атомарность не гарантируется (если только источник специально не предназначен для нее, например CopyOnWriteArrayList).

РЕДАКТИРОВАТЬ: на самом деле, если предположить, что вы не синхронизируете свои потоки должным образом, копирование массива с одним потоком, пока другой поток обновляет ссылки в нем, проблематично в модели памяти Java и теоретически может привести к непредсказуемому поведению.

1
ответ дан 4 December 2019 в 11:40
поделиться

Thread safe и ConcurrentModificationException - это разные понятия. Потокобезопасный объект - это объект, у которого несколько потоков могут одновременно вызывать его методы, а данные, хранящиеся в объекте, гарантированно не будут повреждены (пример: http://thejavacodemonkey.blogspot.com/2007/08/making-your-java-class-thread-safe.html). Исключение ConcurrentModificationException возникает, когда, например, вы выполняете итерацию по коллекции, и коллекция изменяется. Изменения могут исходить из другого потока или из того же потока.

В вашем конструкторе, если другой поток изменит someCollection, пока ваш конструктор копирует ее, это может привести либо к неопределенному поведению (т.е. к повреждению данных в вашей новой коллекции, потому что коллекции не являются потокобезопасными), либо к ConcurrentModificationException (если коллекция обнаружит одновременное изменение, но это не гарантировано, потому что она не является потокобезопасной. ... :-)

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

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

5
ответ дан 4 December 2019 в 11:40
поделиться
Другие вопросы по тегам:

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