Путь к тому, чтобы стать богом, требует стойкого одиночества и начала пути обобщения исходного кода.
Цель чтения и обобщения исходного кода не в том, чтобы продемонстрировать свои навыки. Я надеюсь, что некоторые проблемы можно решить, читая исходный код, и я также могу понять мысли других, читая исходный код, чтобы помочь мы напишем наш код лучше.
Введение
В многопоточном сценарии то, как нам нужно синхронизировать данные, обычно обрабатывается с помощью synchronized или lock, Использование synchronized означает переключение состояния ядра. Это тяжелая операция. Есть ли способ легко реализовать простую синхронизацию данных, например, счетчики и т.д. Пакет atomic под concurrent предоставляет нам такой облегченный вариант синхронизации данных.
Камень других гор
- Давайте поговорим о классе Unsafe в Java:Блог Woohoo.cn on.com/PKU fork/afraid/just…
- Небезопасно для магии Java:О, управление оружием.GitHub.IO/2016/12/31/…
- Пример реализации оптимистической блокировки Java:blog.CSDN.net/Чжан Дэхуа 6…
- Проблемы параллелизма в Java — оптимистическая блокировка и пессимистическая блокировка, а также реализация оптимистической блокировки — CAS:woo woo woo.cn blog on.com/rescue А Чжэн все больше/боится/6…
- Анализ LongAdder серии JDK8:woooooo.brief.com/afraid/EC045 от 38 ох…
- Изучение исходного кода jdk1.8 LongAdder:blog.CSDN.net/U011392897/…
Пример использования
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.atomic.AtomicInteger;
public class App {
public static void main(String[] args) throws Exception {
CountDownLatch countDownLatch = new CountDownLatch(100);
AtomicInteger atomicInteger = new AtomicInteger(0);
for (int i = 0; i < 100; i++) {
new Thread() {
@Override
public void run() {
atomicInteger.getAndIncrement();
countDownLatch.countDown();
}
}.start();
}
countDownLatch.await();
System.out.println(atomicInteger.get());
}
}
Пожалуйста, пока игнорируйте CountDownLatch, просто подождите, пока все дочерние потоки закончат выполнение в основном потоке, и распечатайте результат. Результат всегда 100. Если вы замените AtomicInteger на Integer, результаты печати в основном будут меньше 100.
принцип
Мы можем взглянуть на код для AtomicInteger
Его значение хранится в volatile int. volatile только гарантирует видимость этой переменной. Его атомарность не гарантируется.Вы можете посмотреть на функцию getAndIncrement, похожую на i++, и вы обнаружите, что вызывается getAndAddInt в UnSafe.
Насколько священна UnSafe? Вы можете обратиться к приведенной выше статье, чтобы понять, что UnSafe предоставляет возможность Java напрямую управлять базовым уровнем. Далее мы можем обнаружить реализацию:
Как гарантировать атомарность:Spin + CAS (оптимистическая блокировка). В этом процессе сравните и обновите значение с помощью compareAndSwapInt, если обновление не удастся, повторно выберите старое значение, а затем обновите.
Преимущества и недостатки
По сравнению с другими блокировками, CAS не выполняет операции режима ядра и имеет некоторые улучшения производительности. Но в то же время вводится вращение.Когда конкуренция замков большая, количество вращений будет увеличиваться. Потребление ресурсов процессора будет высоким.
Другими словами, CAS+ spin подходит для использования в сценариях приложений с низким уровнем параллелизма и синхронных данных.
Улучшения и усилия, сделанные jdk8
В jdk8 были введены четыре новых типа счетчиков: LongAdder, LongAccumulator, DoubleAdder, DoubleAccumulator. Все они унаследованы от Striped64.
В чем разница между LongAdder и AtomicLong? Проблема с Atomic* заключается в том, что его можно использовать только в сценариях с низким параллелизмом. Поэтому LongAddr вводит концепцию блокировки сегмента на этой основе. Вы можете обратиться к «Анализу LongAdder серии JDK8», чтобы увидеть, что было сделано.
Вероятно, когда конкуренция не жесткая, все потоки модифицируют одну и ту же переменную (Base) через CAS, а когда конкуренция жесткая, они будут модифицироваться в соответствии с хэшем текущего потока в ячейку (многосегментная блокировка).
Видно, что приближенный принцип реализации таков: черезОптимистическая блокировка CASАтомарность гарантируется черезвращениеУбедитесь, что окончательная модификация текущей модификации выполнена успешно, и увеличьте производительность параллелизма, **уменьшив степень детализации блокировки (многосегментная блокировка)**.
ключевой момент
- вращение
- Оптимистическая блокировка CAS
- Многосегментный замок (идея «разделяй и властвуй»)