AtomicInteger lazySet против набора

В чем разница между методами lazySet и set AtomicInteger? документация не может многое сказать о lazySet:

В конце концов задается заданное значение.

Кажется, что сохраненное значение не будет немедленно установлено на нужное значение, но вместо этого будет запланировано установить некоторое время в будущем. Но каково практическое использование этого метода? Любой пример?

Ответ 1

Прямо из Ошибка 6275329:

Как возможно, последнее небольшое наблюдение за JSR166 для Mustang, мы добавили метод "lazySet" к классам Atomic (AtomicInteger, AtomicReference и т.д.). Это ниша метод, который иногда полезен при тонкой настройке кода, используя неблокирующие структуры данных. Семантика что запись гарантированно не будет переупорядочена с любыми предыдущая запись, но может быть переупорядочена с последующими операциями (или, что то же самое, может не отображаться для других потоков) до происходит некоторое другое летучее действие записи или синхронизации).

Основной вариант использования - обнуление полей узлов в неблокирующие структуры данных исключительно для того, чтобы избежать долгосрочное удержание мусора; он применяется, когда он безвреден если другие потоки некоторое время видят ненулевые значения, но вы чтобы гарантировать, что в конечном итоге структуры GCable. В таком случаев, вы можете получить лучшую производительность, избегая затраты на нуль-volatile-write. Есть несколько другие варианты использования в этих строках для неосновных атомы, так что метод поддерживается во всех Класс AtomicX.

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

Ответ 2

lazySet может использоваться для связи между потоками rmw, потому что xchg является атомарным, так как для видимости, когда процесс потока писем изменяет местоположение строки кэша, процессор потока чтения будет видеть его при следующем чтении, потому что протокол согласованности кеширования intel cpu будет гарантировать, что LazySet работает, но строка кэша будет обновляться при следующем чтении, опять же, процессор должен быть достаточно современным.

http://sc.tamu.edu/systems/eos/nehalem.pdf Для Nehalem, который является многопроцессорной платформой, процессоры имеют возможность "snoop" (подслушивать) адресную шину для доступа других процессоров к системной памяти и к их внутренним кэшам. Они используют эту способность отслеживания, чтобы сохранить свои внутренние тайники как в системной памяти, так и в кэшах в других взаимосвязанных процессорах. Если через отслеживание одного процессора обнаруживается, что другой процессор намеревается записать в ячейку памяти, которую он в настоящее время кэшировал в общем состоянии, процессор отслеживания сделает недействительным свой блок кэша, заставляя его выполнять кеш-строку, заполняя при следующем обращении к той же ячейке памяти.

oracle hotspot jdk для архитектуры x86 cpu →

lazySet == unsafe.putOrderedLong == xchg rw (инструкция asm, которая служит в качестве мягкого барьера стоимостью 20 циклов на процессоре nehelem intel)

на x86 (x86_64) такой барьер намного дешевле, чем волатильный или AtomicLong getAndAdd,

В одном из производителей, один сценарий очереди потребителей, мягкий барьер xchg может заставить строку кодов до того, как lazySet (последовательность + 1) для потока производителя произойдет до того, как любой код потребительского потока будет потреблять (работать) с новыми данными, конечно, потребительский поток должен будет проверить атомарно, что последовательность производителей была увеличена ровно одним, используя compareAndSet (последовательность, последовательность + 1).

Я проследил после исходного кода Hotspot, чтобы найти точное сопоставление lazySet с кодом cpp: http://hg.openjdk.java.net/jdk7/jdk7/hotspot/file/9b0ca45cd756/src/share/vm/prims/unsafe.cpp Unsafe_setOrderedLong → SET_FIELD_VOLATILE definition → OrderAccess: release_store_fence. Для x86_64 OrderAccess: release_store_fence определяется как использование инструкции xchg.

Вы можете увидеть, как это точно определено в jdk7 (doug lea работает над некоторыми новыми материалами для JDK 8): http://hg.openjdk.java.net/jdk7/jdk7/hotspot/file/4fc084dac61e/src/os_cpu/linux_x86/vm/orderAccess_linux_x86.inline.hpp

вы также можете использовать hdis для демонтажа сборки кода lazySet в действии.

Возникает другой вопрос: Нам нужно mfence при использовании xchg

Ответ 3

Более широкое обсуждение истоков и полезности lazySet и базового putOrdered можно найти здесь: http://psy-lob-saw.blogspot.co.uk/2012/12/atomiclazyset-is-performance-win-for.html

Подводя итог: lazySet - это слабая волатильная запись в том смысле, что она действует как магазин-магазин, а не забор для хранения. Это сводится к тому, что lazySet является JIT, скомпилированным для команды MOV, которая не может быть повторно заказана компилятором, а не значительно более дорогой инструкцией, используемой для энергозависимого набора.

При чтении значения вы всегда делаете волатильное чтение (с Atomic *.get() в любом случае).

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

Ответ 4

Из Контекстно-атомная сводка пакетов

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

Если вам интересно узнать о lazySet, тогда вы также должны объяснять себе другие объяснения.

Эффекты памяти для доступа и обновлений атоматики в целом следуйте правилам для летучих, как указано в разделе 17.4 "Java ™" Спецификация языка.

get имеет эффект памяти при чтении изменчивой переменной.

set имеет эффекты памяти записи (назначения) изменчивой переменной.

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

weakCompareAndSet атомарно считывает и условно записывает переменную, но не создает каких-либо событий - до упорядочения, поэтому предоставляет никаких гарантий в отношении предыдущих или последующих чтений и записей любых переменных, кроме целевого объекта weakCompareAndSet.     compareAndSet и все другие операции чтения и обновления, такие как getAndIncrement, имеют эффекты памяти как чтения, так и записи летучие переменные.

Ответ 5

Вот мое понимание, исправьте меня, если я ошибаюсь: Вы можете думать о lazySet() как о "полу" volatile: это в основном переменная, не изменяющаяся по времени, с точки зрения чтения другими потоками, то есть значение, установленное lazySet, может не отображаться для других потоков. Но он становится изменчивым, когда происходит другая операция записи (может быть из других потоков). Единственное влияние lazySet, которое я могу себе представить, это compareAndGet. Поэтому, если вы используете lazySet(), get() из других потоков может по-прежнему получать старое значение, но compareAndGet() всегда будет иметь новое значение, так как это операция записи.

Ответ 6

Re: попытка заглушить его -

Вы можете думать об этом как о способе обработки изменчивого поля, как если бы он не был изменен для определенного хранилища (например: ref = null;).

Это не совсем точно, но этого должно быть достаточно, чтобы вы могли принять решение между "ОК, мне действительно все равно" и "Хм, позвольте мне немного подумать об этом".