Обзор
Атомарная операция относится к операции, которая не прерывается механизмом планирования потока.Как только эта операция начинается, она выполняется до конца без какого-либо переключения контекста потока между ними.
Атомарная операция может состоять из одного или нескольких шагов, но ее порядок не может быть нарушен или ее нельзя сократить для выполнения только ее части.Обработка всей операции как целого является основной особенностью атомарности.
В Java предусмотрено множество атомарных классов, и автор в основном делит эти атомарные классы на четыре категории.
Атомарное обновление примитивных или ссылочных типов
Если это базовый тип, замените его значение, если это ссылка, замените его адрес ссылки.Эти классы в основном включают:
(1) атомарное логическое значение
Атомарно обновляет логический тип.Внутренне значение типа int используется для хранения 1 и 0 для представления true и false.Нижний уровень также является атомарной операцией над типом int.
(2) Атомное целое
Атомарно обновляет тип int.
(3) атомная длинная
Атомное обновление длинного типа.
(4) Атомная ссылка
Ссылочный тип атомарного обновления, указывающий класс для работы с помощью дженериков.
(5) AtomicMarkableReference
Ссылочный тип атомарного обновления использует Pair внутри для переноса ссылочного объекта и отметки о том, был ли он обновлен, что позволяет избежать проблемы ABA.
(6) AtomicStampedReference
Ссылочный тип атомарного обновления использует Pair внутри для переноса ссылочного объекта и обновленного почтового штемпеля, что позволяет избежать проблемы ABA.
Операции этих классов в основном аналогичны.Нижний слой реализуется вызовом compareAndSwapXxx() из Unsafe.Основное использование выглядит следующим образом:
private static void testAtomicReference() {
AtomicInteger atomicInteger = new AtomicInteger(1);
atomicInteger.incrementAndGet();
atomicInteger.getAndIncrement();
atomicInteger.compareAndSet(3, 666);
System.out.println(atomicInteger.get());
AtomicStampedReference<Integer> atomicStampedReference = new AtomicStampedReference<>(1, 1);
atomicStampedReference.compareAndSet(1, 2, 1, 3);
atomicStampedReference.compareAndSet(2, 666, 3, 5);
System.out.println(atomicStampedReference.getReference());
System.out.println(atomicStampedReference.getStamp());
}
Атомарно обновить элемент в массиве
Атомарно обновляет элементы в массиве и может обновлять элементы в указанной позиции индекса в массиве.Эти классы в основном включают:
(1) AtomicIntegerArray
Атомарно обновляет элемент в массиве int.
(2) AtomicLongArray
Атомарно обновляет элемент в длинном массиве.
(3) Массив атомарных ссылок
Атомарно обновляет элемент в массиве объектов.
Операции этих классов в основном аналогичны.При обновлении элементов необходимо указывать позицию индекса в массиве.Основное использование следующее:
private static void testAtomicReferenceArray() {
AtomicIntegerArray atomicIntegerArray = new AtomicIntegerArray(10);
atomicIntegerArray.getAndIncrement(0);
atomicIntegerArray.getAndAdd(1, 666);
atomicIntegerArray.incrementAndGet(2);
atomicIntegerArray.addAndGet(3, 666);
atomicIntegerArray.compareAndSet(4, 0, 666);
System.out.println(atomicIntegerArray.get(0));
System.out.println(atomicIntegerArray.get(1));
System.out.println(atomicIntegerArray.get(2));
System.out.println(atomicIntegerArray.get(3));
System.out.println(atomicIntegerArray.get(4));
System.out.println(atomicIntegerArray.get(5));
}
Поле атомарного обновления в объекте
Атомарно обновить поля в объекте, вы можете обновить поля указанных имен полей в объекте, эти классы в основном включают:
(1) AtomicIntegerFieldUpdater
Атомарно обновить поле типа int в объекте.
(2) AtomicLongFieldUpdater
Атомарно обновляет поле типа long в объекте.
(3) AtomicReferenceFieldUpdater
Атомарное обновление полей ссылочного типа в объекте.
Операции этих классов в основном схожи, и все они должны передавать имя поля, которое нужно обновить.Основное использование заключается в следующем:
private static void testAtomicReferenceField() {
AtomicReferenceFieldUpdater<User, String> updateName = AtomicReferenceFieldUpdater.newUpdater(User.class, String.class,"name");
AtomicIntegerFieldUpdater<User> updateAge = AtomicIntegerFieldUpdater.newUpdater(User.class, "age");
User user = new User("tong ge", 21);
updateName.compareAndSet(user, "tong ge", "read source code");
updateAge.compareAndSet(user, 21, 25);
updateAge.incrementAndGet(user);
System.out.println(user);
}
private static class User {
volatile String name;
volatile int age;
public User(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "name: " + name + ", age: " + age;
}
}
Высокопроизводительный атомный класс
Высокопроизводительные атомарные классы — это атомарные классы, добавленные в java8.Они используют идею сегментации, хэшируют разные потоки в разные сегменты для обновления и, наконец, добавляют значения этих сегментов для получения конечного значения.Эти классы в основном включают :
(1) Полосатый64
Родительский класс следующих четырех классов.
(2) Длинный аккумулятор
Агрегатору длинного типа необходимо передать двоичную операцию длинного типа, которую можно использовать для вычисления различных операций агрегирования, включая сложение и умножение.
(3) Длинный сумматор
Аккумулятор типа long, частный случай LongAccumulator, может использоваться только для вычисления сложения, и вычисление начинается с 0.
(4) Двойной аккумулятор
Агрегатор типа double должен передавать двоичную операцию типа double, которую можно использовать для вычисления различных операций агрегирования, включая сложение и умножение.
(5) ДаблАддер
Аккумуляторы типа double, частный случай DoubleAccumulator, могут использоваться только для вычисления сложений и начинаются с 0.
Операции этих классов в основном схожи.Нижний слой DoubleAccumulator и DoubleAdder фактически реализуется long.Основное использование выглядит следующим образом:
private static void testNewAtomic() {
LongAdder longAdder = new LongAdder();
longAdder.increment();
longAdder.add(666);
System.out.println(longAdder.sum());
LongAccumulator longAccumulator = new LongAccumulator((left, right)->left + right * 2, 666);
longAccumulator.accumulate(1);
longAccumulator.accumulate(3);
longAccumulator.accumulate(-4);
System.out.println(longAccumulator.get());
}
вопрос
Что касается проблем атомарных классов, то автор разобрал следующее:
(1) Что небезопасно?
(3) Почему небезопасно небезопасно?
(4) Как получить экземпляр Unsafe?
(5) Небезопасная работа CAS?
(6) Небезопасная операция блокировки/пробуждения?
(7) Небезопасно создавать экземпляр класса?
(8) Шесть способов создать экземпляр класса?
(9) Что такое атомарная операция?
(10) Связь между атомарными операциями и A в базе данных ACID?
(11) Как AtomicInteger реализует атомарные операции?
(12) Какую проблему в основном решает AtomicInteger?
(13) Каковы недостатки AtomicInteger?
(14) Что такое АВА?
(15) Вред АБК?
(16) РЕШЕНИЕ ДЛЯ ABA?
(17) Как AtomicStampedReference решает ABA?
(18) Сталкивались ли вы с проблемами ABA в реальной работе?
(19) Какова архитектура кэш-памяти ЦП?
(20) Что такое кэш-линия ЦП?
(21) Что такое барьер памяти?
(22) Что вызывает ложное совместное использование?
(23) Как избежать ложного обмена?
(24) Устранить применение ложного обмена в java?
(25) Как реализован LongAdder?
(26) Как LongAdder устраняет ложное совместное использование?
(27) Сравнение производительности между LongAdder и AtomicLong?
(28) Является ли массив ячеек в LongAdder бесконечно расширяемым?
Есть почти так много вопросов об атомах, можете ли вы ответить на них? Щелкните ссылку ниже, чтобы перейти непосредственно к соответствующей главе:
Небезопасный анализ мертвого магического класса Java
Анализ исходного кода AtomicInteger мертвого атомарного класса Java
Анализ исходного кода AtomicStampedReference мертвого класса атома Java
Разное Что такое ложный обмен?
Анализ исходного кода LongAdder мертвого атомарного класса Java
пасхальные яйца
Это конец анализа исходного кода серии атомарных классов.Хотя проанализировано несколько классов, он включает в себя много контента, особенно базовые знания об операционной системе, такие как инструкции ЦП, архитектура кэш-памяти ЦП, барьеры памяти, и т.п.
В следующей главе мы войдем в "серию синхронизации". Наиболее распространенная синхронизация - это различные блокировки. Здесь мы сосредоточимся на анализе различных блокировок, различных синхронизаторов и распределенных блокировок в java.
Добро пожаловать, чтобы обратить внимание на мою общедоступную учетную запись «Брат Тонг читает исходный код», проверить больше статей из серии исходного кода и поплавать в океане исходного кода с братом Тонгом.