Ответ 1
Когда вы передаете свой список в другой поток потокобезопасными средствами (например, используя синхронизированный блок, переменную volatile или AtomicReference
), гарантируется, что второй поток видит весь список в состоянии, в котором он был при передаче (или в любом более позднем состоянии, но не в более раннем состоянии).
Если вы не измените его впоследствии, вам также не понадобится ваш synchronizedList.
Изменить (после некоторых комментариев, чтобы сделать резервную копию моей заявки):
Я предполагаю следующее:
-
У нас есть изменчивая переменная
list
.volatile List<String> list = null;
-
Тема А:
- создает список L и заполняет L элементами.
- устанавливает
list
, чтобы указать на L (это означает запись L вlist
) - не вносит никаких изменений в L.
Пример источника:
public void threadA() { List<String> L = new ArrayList<String>(); L.add("Hello"); L.add("World"); list = l; }
-
Тема B:
- читает K из
list
- выполняет итерацию над K, печатая элементы.
Пример источника:
public void threadB() { List<String> K = list; for(String s : K) { System.out.println(s); } }
- читает K из
-
Все остальные темы не касаются списка.
Теперь мы имеем это:
- Действия 1-A и 2-A в потоке A упорядочены по порядку программы, так что 1 до 2.
- Действие 1-B и 2-B в потоке B упорядочивается порядок программы, так что 1 до 2.
- Действие 2-A в потоке A и действие 1-B в потоке упорядочиваются порядок синхронизации, поэтому 2-A приходит до 1 -B, поскольку
Запись в изменчивую переменную (§8.3.1.4) v синхронизируется со всеми последующими чтениями v любым потоком (где последующее определяется в соответствии с порядком синхронизации).
-
происходит до -order - это транзитивное закрытие программных заказов отдельных потоков и порядка синхронизации. Итак, мы имеем:
1-A происходит до того, как произойдет 2-A - до того, как произойдет 1-B - до 2-B
и, таким образом, 1-A происходит до 2-B.
- Наконец,
Если одно действие происходит - перед другим, то первое видно и упорядочивается до второго.
Итак, наша итерационная нить действительно может видеть весь список, а не только некоторые его части. Таким образом, передача списка с одной изменчивой переменной достаточна, и нам не нужна синхронизация в этом простом случае.
Еще одно редактирование (здесь, поскольку у меня больше свободы форматирования, чем в комментариях) о порядке программы Thread A. (Я также добавил пример кода выше).
Из JLS (раздел порядок программы):
Среди всех действий между потоками, выполняемых каждым потоком t, порядок программы of t - это полный порядок, который отражает порядок, в котором эти действия будут выполняется в соответствии с семантикой внутри потока t.
Итак, что такое внутрипоточная семантика потока A?
Некоторые пункты выше:
Модель памяти определяет, какие значения могут быть прочитаны в каждой точке программы. Действия каждого потока в изоляции должны вести себя как управляемые семантикой этого потока, за исключением того, что значения, наблюдаемые каждым чтением, определяемой моделью памяти. Когда мы говорим об этом, мы говорим, что программа подчиняется семантике внутри потока. Семантика внутри потока - это семантика для однопоточные программы и позволяют полностью прогнозировать поведение поток, основанный на значениях, видимых действиями чтения в потоке. Определить если действия потока t при выполнении являются законными, мы просто оцениваем реализация потока t, как это было бы выполнено в одном поточном контексте, как определено в остальной части этой спецификации.
Остальная часть этой спецификации включает раздел 14.2 (Блоки):
Блок выполняется путем выполнения каждого объявления локальной переменной операторов и других операторов в порядке от первого до последнего (слева направо).
Итак, порядок программы действительно является порядком, в котором выражения/выражения приведены в исходном коде программы.
Таким образом, в нашем примере источник действия памяти создают новый ArrayList, добавляют "Hello", добавляют "World" и присваивают list
(первые три состоят из большего количества подделок) действительно находятся в this порядок программы.
(В VM не нужно выполнять действия в этом порядке, но этот порядок программ по-прежнему вносит вклад в порядок дел и, следовательно, на видимость для других потоков.)