(201) Принцип атомарной* реализации

Java задняя часть .NET HTTPS

Путь к тому, чтобы стать богом, требует стойкого одиночества и начала пути обобщения исходного кода.

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

Введение

В многопоточном сценарии то, как нам нужно синхронизировать данные, обычно обрабатывается с помощью synchronized или lock, Использование synchronized означает переключение состояния ядра. Это тяжелая операция. Есть ли способ легко реализовать простую синхронизацию данных, например, счетчики и т.д. Пакет atomic под concurrent предоставляет нам такой облегченный вариант синхронизации данных.

Камень других гор

Пример использования

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

image.png
Его значение хранится в volatile int. volatile только гарантирует видимость этой переменной. Его атомарность не гарантируется.

Вы можете посмотреть на функцию getAndIncrement, похожую на i++, и вы обнаружите, что вызывается getAndAddInt в UnSafe.

image.png

Насколько священна UnSafe? Вы можете обратиться к приведенной выше статье, чтобы понять, что UnSafe предоставляет возможность Java напрямую управлять базовым уровнем. Далее мы можем обнаружить реализацию:

image.png

Как гарантировать атомарность:Spin + CAS (оптимистическая блокировка). В этом процессе сравните и обновите значение с помощью compareAndSwapInt, если обновление не удастся, повторно выберите старое значение, а затем обновите.

Преимущества и недостатки

По сравнению с другими блокировками, CAS не выполняет операции режима ядра и имеет некоторые улучшения производительности. Но в то же время вводится вращение.Когда конкуренция замков большая, количество вращений будет увеличиваться. Потребление ресурсов процессора будет высоким.

Другими словами, CAS+ spin подходит для использования в сценариях приложений с низким уровнем параллелизма и синхронных данных.

Улучшения и усилия, сделанные jdk8

В jdk8 были введены четыре новых типа счетчиков: LongAdder, LongAccumulator, DoubleAdder, DoubleAccumulator. Все они унаследованы от Striped64.

В чем разница между LongAdder и AtomicLong? Проблема с Atomic* заключается в том, что его можно использовать только в сценариях с низким параллелизмом. Поэтому LongAddr вводит концепцию блокировки сегмента на этой основе. Вы можете обратиться к «Анализу LongAdder серии JDK8», чтобы увидеть, что было сделано.

Вероятно, когда конкуренция не жесткая, все потоки модифицируют одну и ту же переменную (Base) через CAS, а когда конкуренция жесткая, они будут модифицироваться в соответствии с хэшем текущего потока в ячейку (многосегментная блокировка).

image.png

Видно, что приближенный принцип реализации таков: черезОптимистическая блокировка CASАтомарность гарантируется черезвращениеУбедитесь, что окончательная модификация текущей модификации выполнена успешно, и увеличьте производительность параллелизма, **уменьшив степень детализации блокировки (многосегментная блокировка)**.

ключевой момент

  • вращение
  • Оптимистическая блокировка CAS
  • Многосегментный замок (идея «разделяй и властвуй»)