У меня вопрос о простой ArrayList, а не synchronizedList или CopyOnWriteArrayList. Их можно использовать с несколькими потоками, которые добавляют и получают элементы безопасным образом, используя блок или метод синхронизации? И если да: в какой точке разница между простым ArrayList с синхронизированным блоком и synchronizedList?Можно использовать простой ArrayList в многопоточной программе?
ответ
Да, можно использовать ArrayList несколькими потоками с использованием синхронизированных блоков или методов. Фактически, вы проверяете исходный код Collections.synchronizedList(), он делает то же самое. Если вы используете один и тот же объект для синхронизированных методов или блоков для каждого типа доступа (get, add, iterate и т. Д.), Это нормально.
Вы можете использовать почти каждый класс в многопоточной программе, если вы правильно охраняете его. В конце концов, было бы практически невозможно сделать каждый кусок кода безопасным для потоков, поэтому приложения должны внедрять безопасность потоков на более высоком уровне.
Это даже в случае использования результата synchronizedList
. Этот список будет синхронизироваться каждый вызов метода, но алгоритмы, требующих более одного вызова сломается без дополнительной синхронизации, в том числе простого
if(!list.contains(x)) {
list.add(x);
}
, как там может быть одновременным обновление в промежутке между этими двумя вызовами методы (это называется check-then-act anti-pattern).
Таким образом, разница между использованием synchronized
блоков с ArrayList
и используя результат Collections.synchronizedList(new ArrayList<>())
является то, что synchronizedList
будет применяться синхронизации на каждом вызове метода, который будет недостаточным, как только операция состоит из нескольких вызовов, в то время как ручной synchronized
блоков предоставить вам полный контроль над тем, когда синхронизировать и какой диапазон кода будет покрыт и в любом случае необходим, даже если вы используете Collections.synchronizedList
...