Вчера я узнал, что неправильно использовал коллекции с concurrency на протяжении многих-многих лет.
Всякий раз, когда я создаю коллекцию, к которой нужно обращаться более чем одним потоком, я обертываю ее в один из методов Collections.synchronized *. Затем, всякий раз, когда вы мутируете коллекцию, я также переношу ее в синхронизированный блок (я не знаю, почему я это делал, я, должно быть, подумал, что я его где-то читал).
Однако, прочитав API более внимательно, кажется, вам нужен синхронизированный блок при повторной сборке. В документах API (для карты):
Обязательно, чтобы пользователь вручную синхронизировал на возвращенной карте при повторении любого из своих представлений коллекции:
И вот небольшой пример:
List<O> list = Collections.synchronizedList(new ArrayList<O>());
...
synchronized(list) {
for(O o: list) { ... }
}
Итак, учитывая это, у меня есть два вопроса:
-
Почему это даже необходимо? Единственное объяснение, о котором я могу думать, это использование итератора по умолчанию вместо управляемого поточно-безопасного итератора, но они могли бы создать потокобезопасный итератор и устранить этот беспорядок, правильно?
-
Что еще важнее, что это такое? Помещая итерацию в синхронизированный блок, вы предотвращаете одновременную итерацию нескольких потоков. Но другой поток может мутировать список при повторении так, как там работает синхронизированный блок? Не будет ли мутировать список где-нибудь еще с винта с итерацией, синхронизирован ли он или нет? Что мне не хватает?
Спасибо за помощь!