Одновременно читать и устанавливать на Java ArrayList (или что-то подобное) - PullRequest
1 голос
/ 06 марта 2011

В Java, если несколько потоков читают значения в java.util.ArrayList и один из них может установить запись, вызывая ArrayList.set(index, newVal), это сработает?(Я объясню, что я имею в виду под «работой»)

Предположим, что размер списка массивов не изменяется (например, он предопределен и заполнен нулем).Также предположим, что только один назначенный поток вызовет метод set.

Я считаю, что он работает нормально, если

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

Ответы [ 6 ]

1 голос
/ 06 марта 2011

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

Точка 2) может быть дана и на практике, но нет никаких гарантий относительно этого в модели памяти Java,Таким образом, вам придется обеспечить это каким-то образом извне.Либо используйте некоторую переменную volatile, чтобы гарантировать связь «произойдет раньше», либо проделайте то же самое с синхронизацией.Существует также метод lazySet() в AtomicReference (и других классах AtomicXXX), который может здесь помочь, но я не уверен, что правильно понял.

1 голос
/ 06 марта 2011

Если вы только устанавливаете значения, не меняя длину, то это, вероятно, хорошо для вашего использования.Из ArrayList Javadoc .

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

Если вы выполнялиструктурные изменения или несколько потоков записывали в ArrayList, тогда вы могли бы использовать Collections.synchronizedList, чтобы получить список безопасных потоков.

0 голосов
/ 13 января 2017

Запись и чтение ссылок всегда являются атомарными, независимо от того, реализованы ли они как 32- или 64-битные значения, так что вы в безопасности там.

Однако работать ГАРАНТИЙНО не потому, что нетне является гарантией того, что реализация ArrayList может не выполнять некоторую служебную работу при получении / установке, даже если длина списка не изменяется.Эта уборка может быть не безопасна.Представьте, например, что вы создаете список массивов и изменяете размер, чтобы никогда не изменять его снова.Неизвестный для вас список массивов откладывает работу, перемещая только несколько элементов из старого резервного массива в новый резервный массив, каждый раз получая / кладя, так что изменение размера выполняется в постоянное время.Набор может поместить значение 0xbeefbabe в новый резервный массив, в то время как параллельное получение передает значение 0xahhhhe11 из старого резервного массива, перезаписывая новое значение.

Также get может "никогда" не увидеть изменение, если достаточно умныйОптимизатор решает использовать агрессивные строки и оптимизировать полученный код.

0 голосов
/ 21 мая 2013

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

Array tempArr = new ArrayList<Object>(yourOldArr);
// modify the tempArray without changing the size
tempArr[0] = element;
yourOldArr = tempArr; // atomic operation

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

0 голосов
/ 07 марта 2011

1) он не генерирует каких-либо исключений, 2) обновленная запись будет в конечном итоге замечена прочитанными потоками.

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

Object array [] = new Object[N];

public void set(int index, Object value){
  array[index] =value;
}

Это, конечно, деталь реализации и гарантируетсяот выпуска к выпуску.Видимость и упорядочение памяти не гарантируются, но если это вас не беспокоит, то простой набор не должен вызывать непредвиденных ошибок (по состоянию на Java 1.6_24)

0 голосов
/ 06 марта 2011

Я думаю, вы можете сделать что-то вроде этого

List list = Collections.synchronizedList(new ArrayList());
      ...
  synchronized(list) {
      Iterator i = list.iterator(); // Must be in synchronized block
      while (i.hasNext())
          foo(i.next());
  }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...