Делает ли неизменяемая оболочка Java-коллекций потокобезопасными?

StackOverflow https://stackoverflow.com/questions/88036

Вопрос

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

Это было полезно?

Решение

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

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

Другие советы

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

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

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

Судя по источнику Collections, похоже, что Unmodifying так и делает. нет сделайте его синхронизированным.

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

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

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

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

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

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

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

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

Обертывание внешнего массива с использованием collections.unmodifiablelist () предотвращает изменение клиента (и, таким образом, делает его безопасным потоком), но внутренние массивы все еще изменяются.

Обертывание внутренних арадировщиков с использованием collections.unmodifiablelist () также предотвращает изменение клиента (и, следовательно, делает их безопасными), что вам нужно.

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

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

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

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

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

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

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

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top