Метод compareAndSet
Метод compareAndSet класса AtomicInteger
атомарно сравнивает текущее значение с ожидаемым.
Если текущее значение равно ожидаемому, метод
устанавливает новое значение и возвращает true.
В противном случае значение не изменяется,
а метод возвращает false. В первый параметр
мы передаем ожидаемое значение (expected),
во второй - новое значение (newValue).
Операция выполняется атомарно, то есть без промежуточных состояний, видимых другим потокам. Это делает метод основой для lock-free алгоритмов и неблокирующих структур данных.
Синтаксис
atomicInteger.compareAndSet(expectedValue, newValue)
Пример
Давайте создадим AtomicInteger со значением
10 и попробуем заменить его на 20,
указав правильное ожидаемое значение:
import java.util.concurrent.atomic.AtomicInteger;
public class Main
{
public static void main(String[] args)
{
AtomicInteger atomic = new AtomicInteger(10);
boolean res = atomic.compareAndSet(10, 20);
System.out.println(res);
System.out.println(atomic.get());
}
}
Результат выполнения кода:
true
20
Пример
А теперь укажем неверное ожидаемое значение.
Текущее значение 10 не равно ожидаемому
5, поэтому замена не произойдет:
import java.util.concurrent.atomic.AtomicInteger;
public class Main
{
public static void main(String[] args)
{
AtomicInteger atomic = new AtomicInteger(10);
boolean res = atomic.compareAndSet(5, 20);
System.out.println(res);
System.out.println(atomic.get());
}
}
Результат выполнения кода:
false
10
Пример
Метод compareAndSet часто используют
в цикле для безопасного обновления значения
без блокировок. Давайте увеличим значение
на 1 с помощью CAS-цикла:
import java.util.concurrent.atomic.AtomicInteger;
public class Main
{
public static void main(String[] args)
{
AtomicInteger atomic = new AtomicInteger(100);
int current;
int next;
do
{
current = atomic.get();
next = current + 1;
}
while (!atomic.compareAndSet(current, next));
System.out.println(atomic.get());
}
}
Результат выполнения кода:
101
Пример
Рассмотрим работу метода в двух потоках. Первый поток успешно меняет значение, а второй - нет, так как ожидаемое значение уже устарело:
import java.util.concurrent.atomic.AtomicInteger;
public class Main
{
public static void main(String[] args) throws InterruptedException
{
AtomicInteger atomic = new AtomicInteger(1);
Thread t1 = new Thread(() -> {
boolean res = atomic.compareAndSet(1, 2);
System.out.println("t1: " + res);
});
Thread t2 = new Thread(() -> {
boolean res = atomic.compareAndSet(1, 3);
System.out.println("t2: " + res);
});
t1.start();
t1.join();
t2.start();
t2.join();
System.out.println(atomic.get());
}
}
Результат выполнения кода:
t1: true
t2: false
2
Смотрите также
-
класс
AtomicInteger,
который хранит атомарное целое число -
метод
get,
который возвращает текущее значение -
метод
set,
который устанавливает новое значение -
метод
incrementAndGet,
который атомарно увеличивает значение на единицу