Модель памяти Java: переупорядочение и параллельные блокировки

Java meomry образцовые мандаты это synchronize блоки, которые синхронизируются на том же мониторе, осуществляют before-after-realtion на переменных, измененных в тех блоках. Пример:

// in thread A
synchronized( lock )
{
  x = true;
}

// in thread B
synchronized( lock )
{
  System.out.println( x );
}

В этом случае гарантировано, что поток B будет видеть x==true пока уже распараллеливают переданный это synchronized- блок. Теперь я нахожусь в процессе для перезаписи большого количества кода для использования более гибкого (и сказанный быть быстрее) привязывается java.util.concurrent, особенно ReentrantReadWriteLock. Таким образом, пример похож на это:

Править: Пример был поврежден, потому что я неправильно преобразовал код, как отмечено матовым b. Зафиксированный следующим образом:

// in thread A
lock.writeLock().lock();
{
  x = true;
}
lock.writeLock().unlock();

// in thread B
lock.readLock().lock();
{
  System.out.println( x );
}
lock.readLock().unlock();

Однако я не видел подсказок в спецификации модели памяти, что такие блокировки также подразумевают упорядочивание nessessary. При изучении реализации это, кажется, полагается на доступ к энергозависимым переменным внутри AbstractQueuedSynchronizer (для реализации солнца, по крайней мере). Однако это не часть никакой спецификации, и кроме того доступ к энергонезависимым переменным не действительно condsidered покрыт барьером памяти, данным этими переменными, не так ли?

Так, вот мои вопросы:

  • Действительно ли безопасно принять то же упорядочивание как со "старым" synchronized блоки?
  • Это документируется где-нибудь?
  • Получает доступ к какой-либо энергозависимой переменной барьер памяти для какой-либо другой переменной?

С уважением, Steffen

--

Комментарий к Yanamon:

Взгляд на следующий код:

// in thread a
x = 1;
synchronized ( a ) { y = 2; }
z = 3;

// in thread b
System.out.println( x );
synchronized ( a ) { System.out.println( y ); }
System.out.println( z );

Из того, что я понял, барьер памяти осуществляет второй вывод для показа 2, но не гарантировал влияние на других переменных...? Таким образом, как это может сравниться с доступом к энергозависимой переменной?

8
задан Steffen Heil 5 April 2010 в 01:29
поделиться

3 ответа

Из API-документа :

Все реализации блокировки должны обеспечивать одинаковую синхронизацию памяти Семантика , обеспечиваемая встроенной блокировкой монитора , как описано в Спецификации языка Java, третье издание (модель памяти 17.4):

 * Успешная операция блокировки имеет те же эффекты синхронизации памяти, что и успешное действие Lock. 
 * Успешная операция разблокировки имеет те же эффекты синхронизации памяти, что и успешное действие Unlock. 
 

Неудачная блокировка и операции разблокировки и операции повторного входа блокировки / разблокировки не требуют каких-либо эффектов синхронизации памяти .

5
ответ дан 5 December 2019 в 15:21
поделиться

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

volatile boolean memoryBarrier = false;
int unguardedValue = 0;

//thread a:
unguardedValue = 10;
memoryBarrier = true;

// thread b
if (memoryBarrier) {
  // unguardedValue is guaranteed to be read as 10;
}

Но все, что было сказано, предоставленный вами пример кода не выглядел так, как будто он действительно использовал ReentrantLock , поскольку он был разработан для использования.

  1. Использование Lock встроенного в Java ключевого слова syncronized фактически делает доступ к блокировке уже однопоточным, поэтому он не дает Lock шанс выполнить любую реальную работу.
  2. Получение снятия блокировки должно выполняться в соответствии с приведенным ниже шаблоном, это описано в документации Java Lock

lock.readLock().lock();
try {
  // Do work
} finally {
  lock.readLock.unlock();
}

1
ответ дан 5 December 2019 в 15:21
поделиться

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

  1. Вы дважды синхронизируете на одном и том же замке - в этом нет необходимости. При использовании реализации Lock вам не нужно использовать блок synchronized .
  2. Стандартная идиома для использования Lock - это делать это в блоке try-finally, чтобы предотвратить случайное снятие блокировки (поскольку блокировка не снимается автоматически при входе в любой блок, в котором вы находитесь, поскольку с синхронизированным блоком ).

Вы должны использовать блокировку примерно так:

lock.lock();
try {
    //do stuff
}
finally { 
    lock.unlock();
}
4
ответ дан 5 December 2019 в 15:21
поделиться
Другие вопросы по тегам:

Похожие вопросы: