Collections.synchronizedList и синхронизированы - PullRequest
65 голосов
/ 27 февраля 2012
List<String> list = Collections.synchronizedList(new ArrayList<String>());
synchronized (list) {
    list.add("message");
}

Действительно ли нужен блок "синхронизированный (список) {}"?

Ответы [ 6 ]

93 голосов
/ 27 февраля 2012

Вам не нужно синхронизироваться, как вы положили в своем примере.ОДНАКО, очень важно, вам нужно синхронизировать список во время его итерации (как отмечено в Javadoc):

Крайне важно, чтобы пользователь вручную синхронизировал возвращаемый список при его итерации:

List list = Collections.synchronizedList(new ArrayList());
...
synchronized(list) {
    Iterator i = list.iterator(); // Must be in synchronized block
    while (i.hasNext())
        foo(i.next());   
}
29 голосов
/ 27 февраля 2012

Зависит от точного содержимого блока synchronized:

  1. Если блок выполняет одну атомарную операцию в списке (как в вашем примере), synchronized является излишним.

  2. Если блок выполняет несколько операций над списком - и ему необходимо поддерживать блокировку на время составной операции - тогда synchronized равен , а не лишнее. Одним из распространенных примеров этого является перебор списка.

20 голосов
/ 27 февраля 2012

Базовый код для метода добавления Collections.synchronizedList:

public void add(int index, E element) {
    synchronized (mutex) {list.add(index, element);}
}

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

16 голосов
/ 24 октября 2012

Также важно отметить, что любые методы, использующие итераторы, например Collections.sort (), также должны быть инкапсулированы внутри синхронизированного блока.

7 голосов
/ 15 января 2013

Читать это Oracle Doc

В нем говорится "Обязательно, чтобы пользователь вручную синхронизировал возвращаемый список при его итерации"

1 голос
/ 20 ноября 2017

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

Согласно JCIP, общие составные действия могут быть

  • итерация
  • навигация
  • put-if-отсутствующий
  • check-then-act

Блок синхронизированного кода OP не является составным действием, поэтому нет разницы, добавьте его или нет.

Давайте возьмем пример из JCIP и изменим его.немного пояснить, почему необходимо защищать составные действия с помощью блокировки.

Есть два метода, которые работают с одной коллекцией list, которая обернута в Collections.synchronizedList

public Object getLast(List<String> list){
    int lastIndex = list.size() - 1;
    return list.get(lastIndex);
}

public void deleteLast(List<String> list){
    int lastIndex = list.size() - 1;
    list.remove(lastIndex);
}

Если методыgetLast и deleteLast вызываются одновременно двумя разными потоками, ниже может произойти чередование, и getLast выдаст ArrayIndexOutOfBoundsException.Предположим, что текущий lastIndex равен 10.

Тема A (deleteLast) -> удалить
Тема B (getLast) --------------------> get

Thread A remove элемент перед операцией get в Thread B. Таким образом, Thread B по-прежнему использует 10 в качестве lastIndex для вызова list.get метода, он приведетк сопутствующей проблеме.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...