Когда вы пытаетесь выполнить какую-либо операцию с глобальной переменной в многопоточном контексте и хотите, чтобы она была атомарной и обеспечивала видимость памяти для других потоков, вам нужно иметь блокировку вокруг этой операции.
Здесь getArray()
возвращает глобальное поле экземпляра Object[] array
.
Итак, в этом примере:
Object[] elements = getArray();
int len = elements.length;
Object[] newElements = Arrays.copyOf(elements, len + 1);
newElements[len] = e;
setArray(newElements);
return true;
Если вокруг этого блока кода нет блокировки и предполагается, что два потока пытаются добавить элемент, в этом случае может случиться, что один поток и второй поток оба прочитают одинаковое значение len
и назначьте новый элемент тому же индексу.
Так, какой бы поток ни назначал новое значение в конце, он будет перезаписывать значение, ранее установленное другим потоком.
Чтобы объяснить далее, скажем, что поток 1 и поток 2 читают одно и то же значение len
, теперь поток 1 продолжает создавать новый массив из Arrays.copyOf(elements, len + 1)
и присваивает значение переменной e
в * 1024. * позиция нового массива.
И до того, как поток может установить новый массив, используя setArray(newElements)
, поток два тем временем продолжает этот процесс с тем же значением len
. Хотя это создаст новый экземпляр массива, но индекс, в котором установлен новый элемент, будет таким же, как len
, используемый потоком один.
Таким образом, когда второй поток использует setArray(newElements)
для установки нового массива с новым значением после первого потока, более раннее значение массива в len
th index будет перезаписано новым набором элементов по нитке два.