Делает ли немодифицируемая оболочка для коллекций java потокобезопасными?

Мне нужно сделать поток ArrayList из ArrayLists безопасным. Я также не могу заставить клиента вносить изменения в коллекцию. Будет ли немодифицируемая оболочка защищать ее от потоков или мне понадобятся две оболочки для коллекции?

17.09.2008 21:49:09
9 ОТВЕТОВ
РЕШЕНИЕ

По-разному. Оболочка будет предотвращать только изменения в коллекции, которую она упаковывает, а не в объекты в коллекции. Если у вас есть ArrayList из ArrayLists, глобальный список, а также каждый из его списков элементов должны быть обернуты по отдельности, и вам также может понадобиться что-то сделать для содержимого этих списков. Наконец, вы должны убедиться, что исходные объекты списка не изменены, поскольку оболочка предотвращает изменения только через ссылку на оболочку, а не на исходный объект.

В этом случае вам НЕ нужна синхронизированная оболочка.

10
17.09.2008 21:54:55
Я так много узнал с тех пор, как разместил этот вопрос. Просто идет, чтобы доказать это только потому, что ответ принят и / или популярен, что он правильный. На многие неправильные ответы этот сайт принимается только потому, что они популярны. Я изменил принятый ответ на этот после того, как узнал больше.
WolfmanDragon 4.02.2009 22:19:06

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

2
17.09.2008 21:52:17

Если посмотреть на источник коллекций, то кажется, что Unmodifiable не синхронизирует его.

static class UnmodifiableSet<E> extends UnmodifiableCollection<E>
                 implements Set<E>, Serializable;

static class UnmodifiableCollection<E> implements Collection<E>, Serializable;

Оболочки синхронизированных классов содержат объект мьютекса для выполнения синхронизированных частей, поэтому похоже, что вам нужно использовать оба, чтобы получить оба. Или сверните свое собственное!

1
17.09.2008 21:53:53

Это необходимо, если:

  1. До сих пор есть ссылка на оригинальный изменяемый список.
  2. Список будет доступен через итератор.

Если вы собираетесь читать из ArrayList только по индексу, вы можете предположить, что это потокобезопасно.

В случае сомнений выбрал синхронизированную обертку.

0
1.11.2011 12:25:04

Не уверен, понял ли я, что вы пытаетесь сделать, но я бы сказал, что ответ в большинстве случаев - «Нет».

Если вы устанавливаете ArrayList для ArrayList и того и другого, внешний и внутренний списки никогда не могут быть изменены после создания (а во время создания только один поток будет иметь доступ к внутреннему и внешнему спискам), они, вероятно, являются потокобезопасными для оболочки (если оба внешние и внутренние списки упакованы таким образом, что их изменение невозможно). Все операции только для чтения на ArrayLists, скорее всего, потокобезопасны. Однако Sun не гарантирует, что они будут поточно-ориентированными (также не для операций только для чтения), поэтому, даже если это может сработать прямо сейчас, в будущем это может прерваться (если Sun создаст некоторое внутреннее кэширование данных для более быстрого доступа для пример).

0
17.09.2008 21:59:13

Я полагаю, что поскольку оболочка UnmodifiableList хранит ArrayList в конечном поле, любые методы чтения в оболочке будут видеть список таким, каким он был, когда оболочка была создана, пока список не был изменен после создания оболочки, и как пока изменяемые списки ArrayLists внутри оболочки не изменены (от чего оболочка не может защитить).

1
17.09.2008 23:51:55

По смежной теме - я видел несколько ответов, предлагающих использовать синхронизированный сбор для обеспечения безопасности потоков. Использование синхронизированной версии коллекции не делает ее «потокобезопасной» - хотя каждая операция (вставка, подсчет и т. Д.) Защищена мьютексом при объединении двух операций, нет гарантии, что они будут выполняться атомарно. Например, следующий код не является потокобезопасным (даже с синхронизированной очередью):

if(queue.Count > 0)
{
   queue.Add(...);
}
5
1.11.2011 12:24:08

Неизменяемый объект по определению является потокобезопасным (при условии, что никто не сохраняет ссылки на исходные коллекции), поэтому синхронизация не требуется.

Обертывание внешнего ArrayList с использованием Collections.unmodifiableList () не позволяет клиенту изменять его содержимое (и, таким образом, делает его безопасным для потоков), но внутренние ArrayLists по-прежнему являются изменяемыми.

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

Сообщите нам, если это решение вызывает проблемы (накладные расходы, использование памяти и т. Д.); другие решения могут быть применимы к вашей проблеме. :)

РЕДАКТИРОВАТЬ: Конечно, если списки изменены, они НЕ являются потокобезопасными. Я предполагал, что дальнейшие правки не будут сделаны.

1
3.07.2011 18:15:57
Однако свернутая коллекция не является неизменяемой, пока другой поток поддерживает ссылку на изменяемую версию. Этот другой поток может изменять коллекцию, и с синхронизацией нет гарантии, что другие потоки увидят изменения.
Eddie 24.01.2009 02:42:26
Эдди: Вы, конечно, правы (за исключением того, что вы имели в виду «без синхронизации»?); В то время я писал код, представляющий списки, доступные только для чтения, и поэтому неявно (но, вероятно, неправильно) предполагал, что дальнейших изменений не будет. Спасибо!
volley 3.07.2011 18:18:42

Это будет поточно-ориентированным, если немодифицируемое представление безопасно публикуется, а модифицируемый оригинал никогда не изменяется (включая все объекты, рекурсивно содержащиеся в коллекции!) После публикации неизменяемого представления.

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

Вы не можете вернуть unmodifiableList (synchonizedList (theList)), если вы все еще намереваетесь получить доступ к списку несинхронизированным впоследствии; если изменяемое состояние совместно используется несколькими потоками, то все потоки должны синхронизироваться при одних и тех же блокировках при обращении к этому состоянию.

1
21.09.2008 13:08:47