Синхронизированный список Java
У меня есть список предварительно заполненных массивов. И у меня есть несколько потоков, которые будут удалять элементы из списка массивов. Каждый поток вызывает метод удаления ниже и удаляет один элемент из списка. Предоставляет ли следующий код мне последовательное поведение?
ArrayList<String> list = Collections.synchronizedList(new ArrayList<String>());
void remove(String item)
{
do something; (doesn't work on the list)
list.remove(item);
}
Спасибо!
Ответы
Ответ 1
Да, просто будьте осторожны, если вы также выполняете итерирование по списку, потому что в этом случае вам нужно будет синхронизировать его. Из Javadoc:
Обязательно, чтобы пользователь вручную выполнял синхронизацию по возвращенному списку при итерации по нему:
List list = Collections.synchronizedList(new ArrayList());
...
synchronized (list) {
Iterator i = list.iterator(); // Must be in synchronized block
while (i.hasNext())
foo(i.next());
}
Или вы можете использовать CopyOnWriteArrayList
, который медленнее для записи, но не имеет этой проблемы.
Ответ 2
Это должно быть хорошо, если вы не требуете, чтобы метод "remove" был атомарным.
Другими словами, если "сделать что-то" проверяет, что элемент отображается более одного раза в списке, например, возможно, что результат этой проверки будет неправильным к моменту достижения следующей строки.
Кроме того, убедитесь, что вы выполняете синхронизацию в списке:
synchronized(list) {
for (Object o : list) {}
}
Как упоминал Питер Лоури, CopyOnWriteArrayList может облегчить вашу жизнь и обеспечить лучшую производительность в высококонкурентной среде.
Ответ 3
От Collections#synchronizedList(List)
javadoc
Возвращает синхронизированный (потокобезопасный) список, поддерживаемый указанным список. Чтобы гарантировать последовательный доступ, важно, чтобы все доступ к списку поддержки выполняется через возвращенный список... Крайне важно, чтобы пользователь вручную синхронизировал в возвращенном списке при повторении по нему. Несоблюдение этого совета может привести к детерминированному поведению.
Ответ 4
У вас могут быть две проблемы с перечнями:
1) Если вы выполняете модификацию в рамках итерации, хотя в среде с монопотоком вы будете иметь ConcurrentModificationException, как в следующем примере:
List<String> list = new ArrayList<String>();
for (int i=0;i<5;i++)
list.add("Hello "+i);
for(String msg:list)
list.remove(msg);
Итак, чтобы избежать этой проблемы, вы можете сделать:
for(int i=list.size()-1;i>=0;i--)
list.remove(i);
2) Вторая проблема может быть многопоточной средой. Как упоминалось выше, вы можете использовать синхронизированный (список), чтобы избежать исключений.
Ответ 5
Это даст последовательное поведение для операций добавления/удаления. Но при повторении вы должны явно синхронизироваться. Обратитесь к этой ссылке
Ответ 6
Да, он будет работать нормально, поскольку у вас есть synchronized
список. Я предлагаю вам использовать CopyOnWriteArrayList
.
CopyOnWriteArrayList<String> cpList=new CopyOnWriteArrayList<String>(new ArrayList<String>());
void remove(String item)
{
do something; (doesn't work on the list)
cpList..remove(item);
}
Ответ 7
synchronized(list) {
for (Object o : list) {}
}