Атомики, CAS и
неблокирующие
алгоритмы
Алексей Федоров, ОК
@23derevo
@23derevo
—  Oracle — 2011–2014
—  Java Compatibility Kit (JCK)
—  OK.ru — since 2014 — Technology Evangelist
—  JUG.ru Group
—  JUG.ru & CodeFreeze — since 2012
—  JPoint & Joker — since 2013
—  Mobius & .NEXT — since 2014
2
3
О чем этот доклад
4
О чем этот доклад
5
Модели
—  Модель с разделяемой памятью
—  Регистры
— Операции: read, write
—  Удобно программировать, все привыкли
—  Модель с передачей сообщений
—  Послать сообщение
—  Похожа на то, как реально работает железо
6
Терминология
—  Нет устоявшейся терминологии
—  Термины:
—  Parallel
—  Concurrent
—  Distributed
7
Виды параллелизма
—  На уровне операционной системы
—  На уровне одной программы / процесса
8
Параллелизм — ОС
—  Слушать музыку и переписываться
в фейсбуке в Одноклассниках
—  При зависании одной программы другие
продолжают работать
—  и т.п.
9
Преимущества параллелизма
—  Использование нескольких ядер/процессоров
—  Да и на 1 ядре тоже! (async I/O)
—  Простота моделирования
—  Абстракция: фреймворк забирает сложность
—  Упрощенная обработка асинхронных событий
—  Более отзывчивые интерфейсы пользователя
—  Event Dispatch Thread (EDT), async calls
10
Параллелизм на уровне
отдельно взятой программы
—  Эффективное использование ресурсов
—  Удобство, простота написания кода
—  Справедливость
—  Обработка запросов пользователей на
серверах соцсети с одинаковым приоритетом
—  Читатели и писатели
— Fairness (честность)
11
Честность
12
Честность
13
Lock lock = new ReentrantLock(true);
Честность
14
Lock lock = new ReentrantLock(true);
Честность
15
Блокировки
—  java.util.concurrent — since Java 5
—  Lock —> ReentrantLock
—  ReadWriteLock —> ReentrantReadWriteLock
—  StampedLock — since Java 8
—  Synchronized method / section
—  wait() / notify() / notifyAll()
16
Блокировки
—  java.util.concurrent
—  Lock —> ReentrantLock
—  ReadWriteLock —> ReentrantReadWriteLock
—  Syncronized method / section
—  wait() / notify() / notifyAll()
17
Общее: ожидание
Проблемы блокировок
—  Взаимоблокировки (Deadlocks)
—  Инверсия приоритетов
—  Надежность — вдруг владелец блокировки
помрет?
—  Performance
—  Параллелизма в критической секции нет!
—  Владелец блокировки может быть вытеснен
планировщиком
18
Закон Амдала
—  α — часть общего объема вычислений,
которую нельзя распараллелить
—  1-α — часть, которую можно распараллелить
—  p — количество потоков
19
Закон Амдала
—  α — часть общего объема вычислений,
которую нельзя распараллелить
—  1-α — часть, которую можно распараллелить
—  p — количество потоков
20
Алгоритмы без блокировок
—  Без препятствий (Obstruction-Free) —
Поток совершает прогресс, если не встречает
препятствий со стороны других потоков
—  Без блокировок (Lock-Free) — гарантируется
системный прогресс хотя бы одного потока
—  Без ожидания (Wait-Free) — каждая операция
выполняется за фиксированное число шагов,
не зависящее от других потоков
21
Консенсус
—  Объект consensus с операцией decide(v):
—  consensus.decide(v) ≠ const
—  Wait-free
—  N Потоков вызывают consensus.decide()
—  i-ый поток вызывает consensus.decide(vi)
—  Каждый поток вызывает не более 1 раза
—  decide() возвращает одно из vi
—  decide() — протокол консенсуса
22
Консенсусное число
—  Мощность консенсуса — максимальное
количество (N) потоков, для которых данный
объект обеспечивает консенсус
—  Консенсусное число примитива синхронизации
— максимальная мощность консенсуса, который
можно построить на базе данного примитива и
некоторого количества атомарных регистров
—  То есть, существует реализация метода
decide для N потоков, использующая данный
примитив как строительный блок
23
Консенсусное число
—  Операции на регистрах — 1
—  Read-Modification-Write (RMW) — 2
—  Common2 Class — коммутируют друг с
другом или перезаписывают друг друга
—  Универсальные операции — ∞
— Сравнение с обменом (CAS):
Compare-And-Swap, Compare-And-Set
24
Compare and Swap
—  Compare-and-swap (CAS)
—  IA32, x64
—  SPARC
—  loadlinked + store-conditional (LL/SC)
—  PowerPC
—  ARM
25
Семантика CAS
26
Типичный паттерн применения
1. Прочитать значение A из переменной V
2. Взять какое-то новое значение B для V
3. Использовать CAS для атомарного изменения V
из A в B до тех пор, пока другие потоки
меняют значение V во время этого процесса
Атомарность Read-Modify-Write реализуется за
счет постоянного мониторинга системы на
предмет постороннего вмешательства
27
Алгоритм 1: неблокирующий счетчик
28
Fast path vs. long path
—  Каждый блок кода может иметь, как минимум,
два пути исполнения: короткий и длинный
—  Lock: contended vs. Uncontended
—  Uncontended Lock:
—  ≥ 1 CAS
—  Другая машинерия вокруг lock
29
Недостатки CAS
—  CAS заставляет потоки, которые его вызывают,
работать в условиях соревнования
(contention)
—  Больше contention = больше бесполезных циклов
процессора, трата процессорного времени
—  Написание корректных и быстрых алгоритмов на
CAS требует специальной подготовки
30
Поддержка CAS в JVM
—  В Java 5 появился JSR166
—  пакет java.util.concurrent
—  пакет java.util.concurrent.atomic
—  На платформах, поддерживающих CAS, JIT-
компилятор делает inline соответствующих
машинных инструкций
—  Load Linked / Store Conditional
—  Интерпретатор использует Spin Lock
31
Atomic variable classes
—  Scalars
—  Field updaters
—  Arrays
—  Compound variables
—  Accumulators
—  since Java 8
32
Scalars
—  AtomicBoolean
—  AtomicInteger
—  AtomicLong
—  AtomicReference
33
AtomicInteger
—  boolean compareAndSet(int expect, int update)
—  int addAndGet(int delta)
—  int getAndDecrement()
—  int getAndIncrement()
—  int incrementAndGet()
—  …
34
Multivariable Invariant
35
Multivariable Invariant
36
Field Updaters
—  AtomicIntegerFieldUpdater
—  Reflection-based updater for volatile int
—  AtomicLongFieldUpdater
—  Reflection-based updater for volatile long
—  AtomicReferenceFieldUpdater
—  Reflection-based updater for object
37
AtomicLongFieldUpdater
—  long addAndGet(T obj, long delta)
—  boolean compareAndSet(T obj, long expect,
long update)
—  long getAndAdd(T obj, long delta)
—  long incrementAndGet(T obj)
38
AtomicLongFieldUpdater
39
AtomicLongFieldUpdater
40
Atomic Arrays
—  AtomicIntegerArray
—  AtomicLongArray
—  AtomicReferenceArray
41
AtomicLongArray
—  long addAndGet(int i, long delta)
—  long getAndAdd(int i, long delta)
—  boolean compareAndSet(int i, long expect,
long update)
—  long incrementAndGet(int i)
—  …
42
Compound Variables
—  AtomicMarkableReference
—  compareAndSet(
V expectedReference, V newReference,
boolean expectedMark, boolean newMark)
—  AtomicStampedReference
—  boolean compareAndSet(
V expectedReference, V newReference,
int expectedStamp, int newStamp)
43
Accumulators
—  DoubleAccumulator
—  DoubleAdder
—  LongAccumulator
—  LongAdder
—  (Striped64)
44
LongAccumulator
—  void accumulate(long x)
—  long get()
—  long getThenReset()
—  Void reset()
45
Неблокирующие алгоритмы
—  Алгоритм называется неблокирующим, если
отказ или остановка любого потока не может
привести к отказу или остановке любого
другого потока
—  Алгоритм называется свободным от блокировок,
если на каждом шаге какой-то поток выполняет
работу (make progress)
—  Аглоритмы на CAS могут быть одновременно
неблокирующими и свободными от блокировок
46
Неблокирующий стек
47
Неблокирующий стек
48
Неблокирующий стек — push
49
Неблокирующий стек — pop
50
Неблокирующая очередь
—  Michael and Scott, 1996
—  Алгоритм неочевидный
—  Потоки помогают друг другу
51
52
Проблема ABA
53
Литература
—  java.util.concurrent.atomic — Java 8 doc
http://docs.oracle.com/javase/8/docs/api/java/util/concurrent/atomic/package-summary.html
—  Brian Goetz,Java Concurrency in Practice
http://www.amazon.com/Java-Concurrency-Practice-Brian-Goetz/dp/0321349601
—  Herlihy, Shavit
The Art of Multiprocessor Programming
http://www.amazon.com/The-Multiprocessor-Programming-Revised-Reprint/dp/0123973376
—  Nitsan Wakart, Degrees of (Lock/Wait) Freedom
http://psy-lob-saw.blogspot.com/2015/05/degrees-of-lockwait-freedom.html
—  OpenJDK sources
54
Questions & Answers
55

Atomics, CAS and Nonblocking algorithms

  • 1.
  • 2.
    @23derevo —  Oracle —2011–2014 —  Java Compatibility Kit (JCK) —  OK.ru — since 2014 — Technology Evangelist —  JUG.ru Group —  JUG.ru & CodeFreeze — since 2012 —  JPoint & Joker — since 2013 —  Mobius & .NEXT — since 2014 2
  • 3.
  • 4.
    О чем этотдоклад 4
  • 5.
    О чем этотдоклад 5
  • 6.
    Модели —  Модель сразделяемой памятью —  Регистры — Операции: read, write —  Удобно программировать, все привыкли —  Модель с передачей сообщений —  Послать сообщение —  Похожа на то, как реально работает железо 6
  • 7.
    Терминология —  Нет устоявшейсятерминологии —  Термины: —  Parallel —  Concurrent —  Distributed 7
  • 8.
    Виды параллелизма —  Науровне операционной системы —  На уровне одной программы / процесса 8
  • 9.
    Параллелизм — ОС — Слушать музыку и переписываться в фейсбуке в Одноклассниках —  При зависании одной программы другие продолжают работать —  и т.п. 9
  • 10.
    Преимущества параллелизма —  Использованиенескольких ядер/процессоров —  Да и на 1 ядре тоже! (async I/O) —  Простота моделирования —  Абстракция: фреймворк забирает сложность —  Упрощенная обработка асинхронных событий —  Более отзывчивые интерфейсы пользователя —  Event Dispatch Thread (EDT), async calls 10
  • 11.
    Параллелизм на уровне отдельновзятой программы —  Эффективное использование ресурсов —  Удобство, простота написания кода —  Справедливость —  Обработка запросов пользователей на серверах соцсети с одинаковым приоритетом —  Читатели и писатели — Fairness (честность) 11
  • 12.
  • 13.
    Честность 13 Lock lock =new ReentrantLock(true);
  • 14.
    Честность 14 Lock lock =new ReentrantLock(true);
  • 15.
  • 16.
    Блокировки —  java.util.concurrent —since Java 5 —  Lock —> ReentrantLock —  ReadWriteLock —> ReentrantReadWriteLock —  StampedLock — since Java 8 —  Synchronized method / section —  wait() / notify() / notifyAll() 16
  • 17.
    Блокировки —  java.util.concurrent —  Lock—> ReentrantLock —  ReadWriteLock —> ReentrantReadWriteLock —  Syncronized method / section —  wait() / notify() / notifyAll() 17 Общее: ожидание
  • 18.
    Проблемы блокировок —  Взаимоблокировки(Deadlocks) —  Инверсия приоритетов —  Надежность — вдруг владелец блокировки помрет? —  Performance —  Параллелизма в критической секции нет! —  Владелец блокировки может быть вытеснен планировщиком 18
  • 19.
    Закон Амдала —  α— часть общего объема вычислений, которую нельзя распараллелить —  1-α — часть, которую можно распараллелить —  p — количество потоков 19
  • 20.
    Закон Амдала —  α— часть общего объема вычислений, которую нельзя распараллелить —  1-α — часть, которую можно распараллелить —  p — количество потоков 20
  • 21.
    Алгоритмы без блокировок — Без препятствий (Obstruction-Free) — Поток совершает прогресс, если не встречает препятствий со стороны других потоков —  Без блокировок (Lock-Free) — гарантируется системный прогресс хотя бы одного потока —  Без ожидания (Wait-Free) — каждая операция выполняется за фиксированное число шагов, не зависящее от других потоков 21
  • 22.
    Консенсус —  Объект consensusс операцией decide(v): —  consensus.decide(v) ≠ const —  Wait-free —  N Потоков вызывают consensus.decide() —  i-ый поток вызывает consensus.decide(vi) —  Каждый поток вызывает не более 1 раза —  decide() возвращает одно из vi —  decide() — протокол консенсуса 22
  • 23.
    Консенсусное число —  Мощностьконсенсуса — максимальное количество (N) потоков, для которых данный объект обеспечивает консенсус —  Консенсусное число примитива синхронизации — максимальная мощность консенсуса, который можно построить на базе данного примитива и некоторого количества атомарных регистров —  То есть, существует реализация метода decide для N потоков, использующая данный примитив как строительный блок 23
  • 24.
    Консенсусное число —  Операциина регистрах — 1 —  Read-Modification-Write (RMW) — 2 —  Common2 Class — коммутируют друг с другом или перезаписывают друг друга —  Универсальные операции — ∞ — Сравнение с обменом (CAS): Compare-And-Swap, Compare-And-Set 24
  • 25.
    Compare and Swap — Compare-and-swap (CAS) —  IA32, x64 —  SPARC —  loadlinked + store-conditional (LL/SC) —  PowerPC —  ARM 25
  • 26.
  • 27.
    Типичный паттерн применения 1. Прочитатьзначение A из переменной V 2. Взять какое-то новое значение B для V 3. Использовать CAS для атомарного изменения V из A в B до тех пор, пока другие потоки меняют значение V во время этого процесса Атомарность Read-Modify-Write реализуется за счет постоянного мониторинга системы на предмет постороннего вмешательства 27
  • 28.
  • 29.
    Fast path vs.long path —  Каждый блок кода может иметь, как минимум, два пути исполнения: короткий и длинный —  Lock: contended vs. Uncontended —  Uncontended Lock: —  ≥ 1 CAS —  Другая машинерия вокруг lock 29
  • 30.
    Недостатки CAS —  CASзаставляет потоки, которые его вызывают, работать в условиях соревнования (contention) —  Больше contention = больше бесполезных циклов процессора, трата процессорного времени —  Написание корректных и быстрых алгоритмов на CAS требует специальной подготовки 30
  • 31.
    Поддержка CAS вJVM —  В Java 5 появился JSR166 —  пакет java.util.concurrent —  пакет java.util.concurrent.atomic —  На платформах, поддерживающих CAS, JIT- компилятор делает inline соответствующих машинных инструкций —  Load Linked / Store Conditional —  Интерпретатор использует Spin Lock 31
  • 32.
    Atomic variable classes — Scalars —  Field updaters —  Arrays —  Compound variables —  Accumulators —  since Java 8 32
  • 33.
  • 34.
    AtomicInteger —  boolean compareAndSet(intexpect, int update) —  int addAndGet(int delta) —  int getAndDecrement() —  int getAndIncrement() —  int incrementAndGet() —  … 34
  • 35.
  • 36.
  • 37.
    Field Updaters —  AtomicIntegerFieldUpdater — Reflection-based updater for volatile int —  AtomicLongFieldUpdater —  Reflection-based updater for volatile long —  AtomicReferenceFieldUpdater —  Reflection-based updater for object 37
  • 38.
    AtomicLongFieldUpdater —  long addAndGet(Tobj, long delta) —  boolean compareAndSet(T obj, long expect, long update) —  long getAndAdd(T obj, long delta) —  long incrementAndGet(T obj) 38
  • 39.
  • 40.
  • 41.
    Atomic Arrays —  AtomicIntegerArray — AtomicLongArray —  AtomicReferenceArray 41
  • 42.
    AtomicLongArray —  long addAndGet(inti, long delta) —  long getAndAdd(int i, long delta) —  boolean compareAndSet(int i, long expect, long update) —  long incrementAndGet(int i) —  … 42
  • 43.
    Compound Variables —  AtomicMarkableReference — compareAndSet( V expectedReference, V newReference, boolean expectedMark, boolean newMark) —  AtomicStampedReference —  boolean compareAndSet( V expectedReference, V newReference, int expectedStamp, int newStamp) 43
  • 44.
    Accumulators —  DoubleAccumulator —  DoubleAdder — LongAccumulator —  LongAdder —  (Striped64) 44
  • 45.
    LongAccumulator —  void accumulate(longx) —  long get() —  long getThenReset() —  Void reset() 45
  • 46.
    Неблокирующие алгоритмы —  Алгоритмназывается неблокирующим, если отказ или остановка любого потока не может привести к отказу или остановке любого другого потока —  Алгоритм называется свободным от блокировок, если на каждом шаге какой-то поток выполняет работу (make progress) —  Аглоритмы на CAS могут быть одновременно неблокирующими и свободными от блокировок 46
  • 47.
  • 48.
  • 49.
  • 50.
  • 51.
    Неблокирующая очередь —  Michaeland Scott, 1996 —  Алгоритм неочевидный —  Потоки помогают друг другу 51
  • 52.
  • 53.
  • 54.
    Литература —  java.util.concurrent.atomic —Java 8 doc http://docs.oracle.com/javase/8/docs/api/java/util/concurrent/atomic/package-summary.html —  Brian Goetz,Java Concurrency in Practice http://www.amazon.com/Java-Concurrency-Practice-Brian-Goetz/dp/0321349601 —  Herlihy, Shavit The Art of Multiprocessor Programming http://www.amazon.com/The-Multiprocessor-Programming-Revised-Reprint/dp/0123973376 —  Nitsan Wakart, Degrees of (Lock/Wait) Freedom http://psy-lob-saw.blogspot.com/2015/05/degrees-of-lockwait-freedom.html —  OpenJDK sources 54
  • 55.