Я просмотрел OpenJDK source code из CopyOnWriteArrayList
и кажется, что все операции записи защищены одной и той же блокировкой, и операции чтения вообще не защищены. Насколько я понимаю, под JMM все обращения к переменной (как чтение, так и запись) должны быть защищены блокировкой или переупорядочением.Как можно CopyOnWriteArrayList быть потокобезопасным?
Например, set(int, E)
метод содержит следующие строки (под замком):
/* 1 */ int len = elements.length;
/* 2 */ Object[] newElements = Arrays.copyOf(elements, len);
/* 3 */ newElements[index] = element;
/* 4 */ setArray(newElements);
get(int)
метод, с другой стороны, только делает return get(getArray(), index);
.
В моем понимании JMM это означает, что get
может наблюдать массив в несогласованном состоянии, если операторы 1-4 переупорядочиваются как 1-2 (новый) -4-2 (copyOf) -3.
Не понимаю ли я JMM или есть ли какие-либо другие объяснения, почему CopyOnWriteArrayList
является потокобезопасным?
Спасибо. Я пропустил тот факт, что массив «volatile». – Fixpoint
Важной деталью является то, что volatile применяется только к самой ссылке массива, а не к содержимому массива. Однако, поскольку все изменения в массиве производятся ** до того, как ** его ссылка опубликована, летучие гарантии распространяются на содержимое массива. – assylias