Нужно ли синхронизировать энергонезависимую переменную? - PullRequest
0 голосов
/ 28 марта 2020

Рассмотрим 2 потока и массив int[] values. Первый поток выполняет:

synchronized (values) {
     values[i] = 58;
}

, в то время как второй поток выполняет:

if (values[i] == 58) {
}

вне блока synchronized.

Если первый поток сначала выполняет values[i]= 58, гарантируется ли, что, если второй поток выполняется немного позже, if второго потока читает 58, даже если второй поток читает values[i] вне блока synchronized?

Ответы [ 2 ]

2 голосов
/ 28 марта 2020

Если первый поток сначала выполняет значения [i] = 58, гарантируется ли, что если второй поток выполнится немного позже, то if второго потока читает 58, хотя второй поток читает значения [i] вне синхронизированного блока?

Нет

Синхронизация таким способом не останавливает другие потоки для одновременного выполнения какой-либо операции над массивом. Однако другим потокам будет запрещено захватывать блокировку массива.

1 голос
/ 28 марта 2020

Вышеупомянутое поведение не гарантируется. Гарантия такой «видимости» на самом деле является предметом отношения случай-до :

Ключом к избежанию ошибок согласованности памяти является понимание отношения случай-до . Это отношение является просто гарантией того, что запись в память одним указанным оператором c видна другому заданному оператору c.

Отношение до и после ( в соответствии с JLS ) может быть достигнуто следующим образом:

  1. Каждое действие в потоке происходит перед каждым действием в этом потоке, которое происходит позже в порядке программы.
  2. Разблокировка (синхронизированный блок или выход из метода ) монитора происходит перед каждой последующей блокировкой (синхронизированный блок или запись метода) того же монитора. И поскольку отношение «происходит до» является транзитивным, все действия потока перед разблокировкой выполняются до того, как все действия, последующие за любым потоком, блокирующим этот монитор.
  3. Запись в энергозависимое поле происходит - перед каждым последующим чтением это же поле. Запись и чтение изменяемых полей имеют эффекты согласованности памяти, аналогичные входящим и выходящим мониторам, но не влекут за собой взаимную блокировку исключения.
  4. Вызов запуска в потоке происходит до любого действия в запущенном потоке.
  5. Все действия в потоке происходят до того, как какой-либо другой поток успешно завершает соединение из этого потока.

Итак, в вашем конкретном случае вам фактически требуется либо синхронизация с использованием общего монитора, либо AtomicIntegerArray , чтобы сделать доступ к массиву потокобезопасным; Модификатор volatile не поможет, поскольку он влияет только на переменную, указывающую на массив, а не на элементы массива ( более подробное объяснение ).

...