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…Источник: Самородки
Авторские права принадлежат автору. Для коммерческих перепечаток, пожалуйста, свяжитесь с автором для получения разрешения, а для некоммерческих перепечаток, пожалуйста, укажите источник.