Что означает «ложный сбой» в AtomicInteger weakCompareAndSet? - PullRequest
17 голосов
/ 10 декабря 2008

В классе Java AtomicInteger есть метод -

boolean weakCompareAndSet(int expect,int update)

В его документации написано:

Может лихорадочно потерпеть неудачу.

Что здесь означает «неумышленно»:

Ответы [ 4 ]

18 голосов
/ 10 декабря 2008

ложно: без видимой причины

Согласно atomic пакет Javadoc:

Атомарные классы также поддерживают метод weakCompareAndSet, который имеет ограниченную применимость.

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

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

Кроме того, weakCompareAndSet не предоставляет гарантий упорядочения, которые обычно необходимы для управления синхронизацией.


Согласно этого потока , это не столько из-за "аппаратного обеспечения / ОС", сколько из-за алгоритма, используемого параметром weakCompareAndSet:

weakCompareAndSet атомарно устанавливает значение для данного обновленного значения, если текущее значение == ожидаемое значение . Может неуспешно провалиться.

В отличие от compareAndSet () и других операций в AtomicX, операция weakCompareAndSet () не создает никаких упорядочиваний до 10 * *.

Таким образом, тот факт, что поток видит обновление AtomicX, вызванное weakCompareAndSet, не означает, что он должным образом синхронизирован с операциями, которые произошли до уязвимости уязвимого узла ().

Вы, вероятно, не хотите использовать этот метод, но вместо этого следует просто использовать compareAndSet; поскольку есть несколько случаев, когда weakCompareAndSet работает быстрее, чем CompareAndSet, и в ряде случаев попытка оптимизировать код с помощью weakCompareAndSet, а не CompareAndSet привнесет в ваш код тонкие и трудные для воспроизведения ошибки синхронизации.


Примечание относительно заказов до и до :

Модель памяти Java (JMM) определяет условия, при которых поток, читающий переменную, гарантированно увидит результаты записи в другом потоке.

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

Упорядочения случайности перед потоками создаются только путем синхронизации по общей блокировке или доступа к общей изменчивой переменной.

В отсутствие порядка «происходит до» у платформы Java есть широкие возможности для отсрочки или изменения порядка, в котором записи в одном потоке становятся видимыми для чтения той же переменной в другом.

6 голосов
/ 14 декабря 2013

Хорошим вариантом использования для weakCompareAndSet являются счетчики производительности - нет необходимости в упорядочении, высокая частота обновлений (так что упорядочение вредно для слабо упорядоченных систем), но при больших нагрузках отсчет не сбрасывается (плотно перегруженные счетчики перфораторов могут сбрасываться 99 % от всех значений, по существу оставляя значение счетчиков относительно случайных неконтролируемых счетчиков случайным).

6 голосов
/ 10 декабря 2008

Это означает, что он может вернуть false (и не будет устанавливать новое значение), даже если в данный момент он содержит ожидаемое значение.

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


Немного конкретнее о том, почему может произойти нечто подобное.

Некоторые архитектуры (например, более новые ARM) реализуют операции CAS с использованием набора инструкций Load Linked (LL) / Store Conditional (SC). Инструкция LL загружает значение в ячейку памяти и «запоминает» адрес где-либо. Инструкция SC сохраняет значение в этой ячейке памяти, если значение по запомненному адресу не было изменено. Аппаратные средства могут полагать, что расположение было изменено, даже если оно, по-видимому, не было по ряду возможных причин (и причины могут различаться в зависимости от архитектуры ЦП):

  1. местоположение может быть написано с тем же значением
  2. разрешение просматриваемых адресов может не совпадать с одной интересующей ячейкой памяти (например, строки кэша). Запись в другое местоположение, которое находится «рядом», может привести к тому, что аппаратное обеспечение пометит рассматриваемый адрес как «грязный»
  3. ряд других причин, которые могут привести к потере ЦП сохраненного состояния инструкции LL - переключение контекста, сброс кеша или изменение таблицы страниц.
0 голосов
/ 10 декабря 2008

Но почему такое вообще допускается? Это потому, что аппаратное обеспечение / ОС под ним глючит? Или за этим стоит какая-то веская техническая причина?

...