AtomicLong
и AtomicInteger
используют CAS для внутреннего использования - сравнивают и устанавливают (или сравнивают и меняют). Идея состоит в том, что вы сообщаете CAS две вещи: значение, которое вы ожидаете от long / int, и значение, которое вы хотите обновить. Если long / int имеет значение, которое, как вы говорите, должно иметь, CAS автоматически выполнит обновление и вернет true
; в противном случае обновление не произойдет, и будет возвращено false
. Многие современные чипы очень эффективно поддерживают CAS на уровне машинного кода; если JVM работает в среде, в которой нет CAS, она может использовать мьютексы (то, что Java называет синхронизацией) для реализации CAS. В любом случае, получив CAS, вы можете безопасно реализовать атомарный инкремент с помощью этой логики (в псевдокоде):
long incrementAndGet(atomicLong, byIncrement)
do
oldValue = atomicLong.get() // 1
newValue = oldValue + byIncrement
while ! atomicLong.cas(oldValue, newValue) // 2
return newValue
Если вошел другой поток и сделал свой собственный шаг между строками // 1
и // 2
, CAS завершится ошибкой, и цикл будет повторен. В противном случае CAS будет успешным.
В таком подходе есть риск: если конкуренция низкая, CAS работает быстрее, чем синхронизированный блок, что не вызывает переключения контекста потока. Но если есть много споров, некоторым потокам придется проходить многократные итерации цикла за приращение, что, очевидно, равносильно потраченной работе. Вообще говоря, incrementAndGet будет быстрее при наиболее распространенных нагрузках.