2013-02-16 2 views
2

в документе Java говорит, что синхронизированная коллекция должна быть снова синхронизирована вручную на итерации. Почему это? Поскольку возвращенная коллекция уже синхронизирована. Не совсем понимаю, почему так. Спасибо.Зачем синхронизировать синхронизацию в синхронизации?

Collection c = Collections.synchronizedCollection(myCollection); 
     ... 
    synchronized(c) { 
     Iterator i = c.iterator(); // Must be in the synchronized block 
     while (i.hasNext()) 
      foo(i.next()); 
    } 

ответ

3

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

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

+0

Тогда в чем смысл синхронизированной коллекции, предоставляемой коллекциями? Если нить A должна сначала «добавить» один элемент, тогда вам нужно проверить «размер», а поток B также получает доступ к коллекции, потенциально добавляя или удаляя. В таком случае, необходимо ли в этом случае поток A также локально синхронизировать коллекцию? – user697911

+0

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

+0

В вашем случае использования, если Thread B только добавляет или удаляет элемент, а Thread A имеет синхронизированный блок вокруг добавления, а затем проверяет размер, нет проблем. Однако, если нет синхронизированного блока, Thread B может добавить/удалить элемент до проверки размера, что было бы проблематичным. Синхронизированная обертка коллекции позволяет случай, когда Thread B не нужно явно указывать какой-либо синхронизированный блок. –

3

Причина в том, что операции итерации не могут держать замок в списке. Например, i.hasNext() заблокирует список до тех пор, пока он не проверит hasNext(), но затем список может быть изменен снова, прежде чем вы сможете позвонить по телефону next().

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

+0

«Операции итерации не могут содержать блокировку в списке». Это потому, что операция итерации не является атомарной, а представляет собой последовательность процессов? Что, если несколько потоков попытаются добавить() что-то в коллекцию? – user697911

+2

Каждый вызов _method является атомарным, но итерация в целом состоит из многих вызовов методов, поэтому он не может быть атомарным, если вы не выполняете синхронизацию самостоятельно. –

0

Представьте, что цикл iterator работает в двух разных потоках. Совершенно очевидно, что один поток вызовет i.next().remove(), тогда как другой поток зациклится на том же list, что может нарушить согласованность данных в списке.

Смежные вопросы