Блокировки как инструмент для одновременного обмена данными и обеспечения согласованности имеют несколько реализаций на платформе JAVA (например, Synchronized, ReentrantLock и т. д.). Эти уже написанные блокировки обеспечивают удобство для нашей разработки, но конкретная природа и тип блокировок редко упоминаются. В этой серии статей будут проанализированы распространенные имена и характеристики блокировок в JAVA, чтобы ответить на ваши вопросы.
1. Спин-блокировка
Спин-блокировки реализуются, позволяя текущему потоку непрерывно выполняться внутри тела цикла. Только когда условия цикла изменяются другими потоками, можно войти в критическую секцию. Скопируйте код следующим образом:
общественный класс SpinLock {
частный знак AtomicReference<Thread> =new AtomicReference<>();
публичная недействительная блокировка(){
Текущий поток = Thread.currentThread();
while(!sign .compareAndSet(null, current)){
}
}
публичная недействительная разблокировка (){
Текущий поток = Thread.currentThread();
знак .compareAndSet(текущий, ноль);
}
}
Используя атомарные операции CAS, функция блокировки устанавливает владельца текущего потока и прогнозирует, что исходное значение пусто. Функция разблокировки устанавливает для владельца значение null, а прогнозируемое значение — это текущий поток.
Когда второй поток вызывает операцию блокировки, поскольку значение владельца не пусто, цикл выполняется до тех пор, пока первый поток не вызовет функцию разблокировки, чтобы установить для владельца значение null, а второй поток не сможет войти в критическую секцию.
Поскольку блокировка вращения сохраняет только текущий поток, выполняющий тело цикла, без изменения состояния потока, скорость ответа выше. Но когда количество потоков продолжает увеличиваться, производительность значительно падает, поскольку каждый поток требует выполнения и отнимает время процессора. Если конкуренция потоков не является интенсивной и блокировка сохраняется в течение определенного периода времени. Подходит для использования со спин-замками.
Примечание. Этот пример представляет собой нечестную блокировку. Порядок получения блокировки не будет зависеть от порядка входа в блокировку.
2. Другие типы спин-локов
Выше мы говорили о спин-блокировках. Существует три распространенные формы спин-блокировок: TicketLock, CLHlock и MCSlock.
Блокировка билетов в основном решает проблему последовательности доступа. Основная проблема возникает на многоядерных процессорах:
Скопируйте код кода следующим образом:
пакет com.alipay.titan.dcc.dal.entity;
импортировать java.util.concurrent.atomic.AtomicInteger;
общественный класс TicketLock {
частный AtomicInteger serviceNum = новый AtomicInteger();
частный AtomicInteger TicketNum = новый AtomicInteger();
частный статический окончательный ThreadLocal<Integer> LOCAL = новый ThreadLocal<Integer>();
публичная недействительная блокировка() {
int myticket = TicketNum.getAndIncrement();
LOCAL.set(мойбилет);
while (myticket != serviceNum.get()) {
}
}
общественная недействительная разблокировка () {
int myticket = LOCAL.get();
serviceNum.compareAndSet(мойтикет, мойтикет + 1);
}
}
Сервисный номер serviceNum должен запрашиваться каждый раз, что влияет на производительность (он должен быть прочитан из основной памяти и необходимо запретить другим процессорам изменять его).
CLHLock и MCSLock — это два похожих типа справедливых блокировок, отсортированных в виде связанного списка.
Скопируйте код кода следующим образом:
импортировать java.util.concurrent.atomic.AtomicReferenceFieldUpdater;
общественный класс CLHLock {
публичный статический класс CLHNode {
частный изменчивый логический isLocked = true;
}
@SuppressWarnings («не используется»)
частный энергозависимый хвост CLHNode;
частный статический окончательный ThreadLocal<CLHNode> LOCAL = новый ThreadLocal<CLHNode>();
частный статический окончательный AtomicReferenceFieldUpdater<CLHLock, CLHNode> UPDATER = AtomicReferenceFieldUpdater.newUpdater(CLHLock.class,
CLHNode.class, "хвост");
публичная недействительная блокировка() {
Узел CLHNode = новый CLHNode();
ЛОКАЛЬНЫЙ.set(узел);
CLHNode preNode = UPDATER.getAndSet(this, node);
если (preNode != ноль) {
в то время как (preNode.isLocked) {
}
преузел = ноль;
ЛОКАЛЬНЫЙ.set(узел);
}
}
общественная недействительная разблокировка () {
Узел CLHNode = LOCAL.get();
if (!UPDATER.compareAndSet(this, node, null)) {
node.isLocked = ложь;
}
узел = ноль;
}
}
CLHlock постоянно запрашивает переменные-предшественники, что делает его непригодным для использования в архитектуре NUMA (в этой архитектуре каждый поток распределен в отдельной области физической памяти).
MCSLock циклически перебирает узлы локальных переменных. С CLHlock проблем нет.
Скопируйте код кода следующим образом:
импортировать java.util.concurrent.atomic.AtomicReferenceFieldUpdater;
общественный класс MCSLock {
публичный статический класс MCSNode {
следующий нестабильный MCSNode;
изменчивое логическое значение isLocked = true;
}
частный статический окончательный ThreadLocal<MCSNode> NODE = новый ThreadLocal<MCSNode>();
@SuppressWarnings («не используется»)
частная энергозависимая очередь MCSNode;
частный статический окончательный AtomicReferenceFieldUpdater<MCSLock, MCSNode> UPDATER = AtomicReferenceFieldUpdater.newUpdater(MCSLock.class,
MCSNode.class, «очередь»);
публичная недействительная блокировка() {
MCSNode currentNode = новый MCSNode();
УЗЕЛ.set(текущийУзел);
MCSNode preNode = UPDATER.getAndSet(this, currentNode);
если (preNode != ноль) {
preNode.next = текущийузел;
в то время как (currentNode.isLocked) {
}
}
}
общественная недействительная разблокировка () {
MCSNode currentNode = NODE.get();
если (currentNode.next == ноль) {
если (UPDATER.compareAndSet(this, currentNode, null)) {
} еще {
в то время как (currentNode.next == ноль) {
}
}
} еще {
currentNode.next.isLocked = ложь;
currentNode.next = ноль;
}
}
}
С точки зрения кода CLH проще, чем MCS.
Очередь CLH является неявной очередью и не имеет реальных атрибутов узла-преемника.
Очередь MCS — это явная очередь с реальными атрибутами узла-преемника.
Блокировкой по умолчанию, используемой внутри JUC ReentrantLock, является блокировка CLH (существует множество улучшений, таких как замена спин-блокировок блокирующими блокировками и т. д.).
(Полный текст заканчивается)