AtomicXXX.lazySet (...) с точки зрения происходит перед краями - PullRequest
16 голосов
/ 26 сентября 2011

Что означает метод AtomicXXX.lazySet (value) с точки зрения границ до появления события, используемый в большинстве рассуждений JMM? Javadocs чист на нем, и ошибка Sun 6275329 гласит:

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

Но это не рассуждения о краях НВ, поэтому меня это смущает. Означает ли это, что семантика lazySet () не может быть выражена в терминах ребер HB?

ОБНОВЛЕНИЕ : Я попытаюсь конкретизировать свой вопрос. Я могу использовать обычное энергозависимое поле в следующем сценарии:

//thread 1: producer
...fill some data structure
myVolatileFlag = 1;

//thread 2: consumer
while(myVolatileFlag!=1){
   //spin-wait
}
...use data structure...

В этом сценарии использование «структуры данных» в потребителе является правильным, поскольку изменяемый флаг записи-чтения делает HB ребром, давая гарантию, что все записи в «структуру данных» по производителю будут завершены и видимы для потребителя. Но что, если я буду использовать AtomicInteger.lazySet / get вместо volatile записи / чтения в этом сценарии?

//thread 1: producer
...fill some data structure
myAtomicFlag.lazySet(1);

//thread 2: consumer
while(myAtomicFlag.get()!=1){
   //spin-wait
}
...use data structure...

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

Это не вопрос "с воздуха" - я видел такой метод в коде LMAX Disruptor именно в этом сценарии, и я не понимаю, как доказать, что это правильно ...

Ответы [ 2 ]

12 голосов
/ 27 сентября 2011

Операции lazySet не создают ребра до появления события и поэтому не гарантируют, что они будут немедленно видны.Это низкоуровневая оптимизация, которая имеет только несколько вариантов использования, которые в основном находятся в параллельных структурах данных.

Пример сборки мусора обнуления указателей на связанный список не имеет видимых для пользователя побочных эффектов.Обнуление является предпочтительным, так что если узлы в списке принадлежат разным поколениям, это не заставляет выполнять более дорогую коллекцию, чтобы отбросить цепочку ссылок.Использование lazySet поддерживает гигиеническую семантику, не вызывая непостоянных накладных расходов на запись.

Другим примером является использование энергозависимых полей, защищаемых блокировкой, таких как ConcurrentHashMap.Поля являются изменяемыми, чтобы разрешить чтение без блокировки, но запись должна выполняться под блокировкой, чтобы обеспечить строгую согласованность.Поскольку блокировка гарантирует крайний случай «до появления» при выпуске, оптимизация заключается в использовании lazySet при записи в поля и сбросе всех обновлений при разблокировке.Это помогает сократить критическую секцию, избегая ненужных остановок и шинного трафика.

Если вы пишете параллельную структуру данных, то lazySet - хороший прием, о котором следует знать.Это низкоуровневая оптимизация, поэтому ее стоит учитывать только при настройке производительности.

3 голосов
/ 26 сентября 2011

На основе Javadoc of Unsafe (putOrderedInt используется в AtomicInteger.lazySet)

/** 
 * Version of {@link #putObjectVolatile(Object, long, Object)}
 * that does not guarantee immediate visibility of the store to
 * other threads. This method is generally only useful if the
 * underlying field is a Java volatile (or if an array cell, one
 * that is otherwise only accessed using volatile accesses).
 */
public native void  putOrderedObject(Object o, long offset, Object x);

/** Ordered/Lazy version of {@link #putIntVolatile(Object, long, int)}  */
public native void  putOrderedInt(Object o, long offset, int x);

Поля поддержки в классах AtomicXXX являются энергозависимыми.Похоже, что lazySet записывает в эти поля, как будто они не являются изменчивыми, что удалит ожидаемые ребра до того, как вы ожидаете.Как отмечено в вашей ссылке, это было бы полезно для того, чтобы значения NULL имели право на сборщик мусора, не подвергаясь изменчивой записи.

Редактировать:

Это ответ на ваше обновление.

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

lazySet не будет упорядочен выше того места, где он записывается.до, но без какой-либо другой фактической синхронизации вы теряете гарантию, что потребитель увидит любые изменения, которые были написаны до него.Совершенно законно откладывать запись myAtomicFlag и туда для любых записей до него, пока не произойдет какая-либо другая форма синхронизации.

...