Какая разница между compareAndSet и weakCompareAndSet в AtomicReference?

Исходный код - это одно и то же.

public final boolean compareAndSet(V expect, V update) {
    return unsafe.compareAndSwapObject(this, valueOffset, expect, update);
}

public final boolean weakCompareAndSet(V expect, V update) {
    return unsafe.compareAndSwapObject(this, valueOffset, expect, update);
}

Какая точка?

Ответ 1

weakCompareAndSet Javadoc объясняет это так:

Атомно устанавливает значение для данного обновленного значения, если текущее value == ожидаемое значение.

Может нерегулярно проваливаться и не дает гарантий упорядочения, поэтому лишь редко является подходящей альтернативой для сравнения AndSet.

Короче говоря, Javadoc говорит, что версия weak является (или была) версией, которая предоставляла "более слабые" гарантии.

Теперь, как вы заметили, текущие реализации этих двух методов идентичны. Это верно для Java 6 - Java 8 (по крайней мере), основываясь на исходном коде на сайте Grepcode.

Поэтому я предполагаю, что реализации этих двух методов были либо:

  • изначально отличался, но сделал то же самое в результате пересмотра реализации Unsafe:

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

Последнее объяснение маловероятно. Если два метода изначально реализованы одинаково, переопределение их как разных может привести к нарушению существующего кода. Это плохая идея, даже для Unsafe.


@assylias/@Стефан Гобель прокомментировал альтернативное объяснение. По сути, "идентичный код", который мы видим в исходном коде, может на самом деле быть переписан компилятором JIT, чтобы дать разный машинный код для двух методов.

Это, безусловно, правдоподобно. JIT-компилятор имеет специальную генерацию кода для некоторых (не нативных) вызовов методов: так называемые "встроенные функции".

Ответ 2

В x86 есть инструкция LOCK CMPXCHG для реализации CAS, которая является атомарной и обеспечивает (near-) максимальные гарантии упорядочения, вы не можете ее ослабить.

Но на других платформах, таких как PowerPC или ARM, реализован CAS в виде последовательности нескольких инструкций, которые предоставляют LL/SC и барьеры памяти в качестве отдельных строительных блоков. Это дает некоторое пространство для маневра, насколько силен ваш CAS как с точки зрения порядка, так и с точки зрения гарантий. И наоборот, это означает, что полнофункциональный CAS является более дорогой последовательностью команд, чем требуется для некоторых алгоритмов параллелизма.

Таким образом, weakcas позволяет вам делать некоторые компромиссы на таких платформах.

Javadoc не совсем ясно, что именно означает ослабленный порядок, поскольку в настоящее время он не может быть выражен в терминах модели памяти Java. Это может быть пересмотрено в будущем, когда оно будет более тесно связано с моделью памяти С++ 11.

Таблица в главе о многопроцессорных процессорах JSR-133 Cookbook содержит обзор различий между платформами.

Ответ 3

Также из документации по Java, похоже, что другие ответы пропустили это:

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

https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/atomic/package-summary.html#weakCompareAndSet

Ответ 4

Функционально оба значения одинаковы. Основное отличие заключается в том, что weakAtomicCompareAndSet может ошибочно (видеть документацию оракула) и не обеспечивает гарантию заказа

Рекомендуется использовать atomicCompareAndSet вместо слабой версии