Подтвердить что ты не робот

Неизменимая оболочка для коллекций java делает их потокобезопасными?

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

4b9b3361

Ответ 1

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

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

Ответ 2

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

if(queue.Count > 0)
{
   queue.Add(...);
}

Ответ 3

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

Ответ 4

От взгляда на источник Коллекций, похоже, что Unmodifiable делает не синхронизацией.

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

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

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

Ответ 5

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

Ответ 6

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

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

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

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

EDIT: Конечно, если списки изменены, они не являются потокобезопасными. Я не предполагал, что дальнейшие изменения не будут сделаны.

Ответ 7

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

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

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

Ответ 8

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

  • По-прежнему существует ссылка на исходный модифицируемый список.
  • Доступ к списку возможен, хотя итератором.

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

Если вы сомневаетесь, выберите синхронизированную упаковку.

Ответ 9

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

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