принцип Java CAS

Java

1. Введение в CAS

1. Что такое КАС?

     Полное название CAS Compare and Swap, то есть сравнивать и обменивать.Он реализует функцию синхронизации многопоточности через атомарные инструкции.Он сравнивает исходное значение, хранящееся в адресе памяти, с заданным адресом памяти.Только когда они равны, заменяется указанный адрес памяти. Ожидаемое значение и значение в памяти. Эта операция является атомарной операцией. Если они не равны, извлекается исходное значение, хранящееся по адресу памяти.

2. Процесс CAS

CAS - это алгоритм без блокировки с 3 ключевыми операндами, адресом памяти, ожидаемым значением в старой памяти, новым значением, которое необходимо обновить, и когда значение памяти и ожидаемое значение в старой памяти равны, обновить значение в памяти это новое значение.

3. Оптимистичная блокировка и пессимистическая блокировка

     CAS относится к оптимистической блокировке. Оптимистическая блокировка заключается в завершении операции без блокировки каждый раз, но при условии отсутствия конфликта. В случае сбоя из-за конфликта он будет повторять попытку, пока не добьется успеха.
     synchronized — это пессимистичная блокировка. После того, как поток получает блокировку, другие потоки должны ждать, пока поток освободит блокировку, что имеет низкую производительность.

Во-вторых, демонстрация кода AtomicInteger.

     В Java a++ не является атомарной операцией. Простая операция a++ включает в себя три операции: получение значения переменной a в памяти, запись переменной a+1 и запись нового значения в память. Это включает два доступа к памяти. В многопоточной среде , будут проблемы безопасности параллелизма.
     AtomicInteger — это класс атомарных операций, внутри которого используется алгоритм CAS без блокировок. Здесь мы анализируем его внутреннюю реализацию.

AtomicInteger atomicInteger = new AtomicInteger(0);
atomicInteger.getAndSet(1);  

     Блок статического кода здесь выполняется перед инициализацией объекта AtomicInteger для получения смещения поля значения объекта AtomicInteger относительно «начального адреса» объекта AtomicInteger. Макет объекта Java, хранящегося в памяти, можно разделить на три области: заголовок объекта (Header), данные экземпляра (Instance Data) и заполнение выравнивания (Padding), смещение «начального адреса» является смещением заголовка объекта.

static {
    try {
        valueOffset = unsafe.objectFieldOffset
            (AtomicInteger.class.getDeclaredField("value"));
    } catch (Exception ex) { throw new Error(ex); }
}
public final int getAndSet(int newValue) {
    return unsafe.getAndSetInt(this, valueOffset, newValue);
}

     Каждый раз по адресу памяти (var2) сначала получайте исходное значение (var5) в памяти из памяти, а затем циклически сравнивайте исходное значение (var5) в памяти с заданным адресом памяти (var2), и если они равны, обновите указанное ожидаемое значение ( var4 ), если оно не равно, повторите попытку, пока не добьетесь успеха, и, наконец, верните старое значение памяти var5.

//var1为AtomicInteger对象,var2为内存地址值,var4为指定的预期值
public final int getAndSetInt(Object var1, long var2, int var4) {
    int var5;
    do {
	//unsafe.getIntVolatile调用本地方法获取内存中值
        var5 = this.getIntVolatile(var1, var2);
    } while(!this.compareAndSwapInt(var1, var2, var5, var4));

    return var5;
}

3. Недостатки

1. Проблема АВА

     Когда CAS работает, он проверяет, было ли изменено значение переменной.Если нет, он обновляет значение, но это приводит к проблеме.Первое значение равно A, затем оно становится B и, наконец, снова становится A. После проверки это значение не было изменено, потому что окончательное значение по-прежнему равно A, но на самом деле это значение действительно было изменено. Чтобы решить эту проблему, номер версии добавляется каждый раз, когда выполняется операция, и каждая операция имеет два значения, номер версии и определенное значение, проблема A—>B—>A становится 1A ——> 2В—>3А. Класс AtomicStampedReference предоставляется в jdk для решения проблемы ABA.Он реализован с помощью внутреннего класса Pair, который содержит два свойства, представляющих номер версии и ссылку.В compareAndSet сначала проверяется текущая ссылка, а затем версия установлен флажок числа Только все Значение обновляется только в том случае, если оно равно.

2. Может гарантировать только атомарные операции над общей переменной.

     При работе с несколькими общими переменными циклический CAS не может гарантировать атомарность операции, и в это время можно использовать блокировки. Начиная с java1.5, JDK предоставляет класс AtomicReference для обеспечения атомарности между ссылочными объектами, так что несколько переменных могут быть помещены в один объект для выполнения операций CAS.

3. Длительное время цикла и высокая нагрузка на ЦП

     В случае высокой степени параллелизма, если множество потоков неоднократно пытаются обновить определенную переменную, но обновление все время завершается сбоем, это создает большую нагрузку на ЦП.

Автор: Тао Чжанхао
Ссылка на сайт:nuggets.capable/post/684490…Источник: Самородки
Авторские права принадлежат автору. Для коммерческих перепечаток, пожалуйста, свяжитесь с автором для получения разрешения, а для некоммерческих перепечаток, пожалуйста, укажите источник.