Upload
alexey-fyodorov
View
725
Download
1
Embed Size (px)
Citation preview
Какпотокипомогаютдругдругу
Алексей Федоров, JUG.ru
Алексей Федоров
about.me/23derevo
Java-конференции JUG.ru Group
Санкт-Петербург3-4 ноября 2017
Москва6-7 апреля 2018
� Программирование� Алгоритмы� Многопоточность
Про что этот доклад
Много интересных докладов в других залах
Новичкам в области многопоточности
SorryПерейдите в другой зал
Про что этот доклад
Новичкам в области многопоточности
SorryПерейдите в другой зал
Новичкам в неблокирующей синхронизации
Короткое введение
Про что этот доклад
Новичкам в области многопоточности
SorryПерейдите в другой зал
Новичкам в неблокирующей синхронизации
Короткое введение
Продвинутым многопоточным программистам
Поговорим о неблокирующейсинхронизации
Про что этот доклад
Модели
Модели
Модель с разделяемой памятью� Операции на атомарных регистрах: read, write� Удобно программировать, все привыкли
Модель с разделяемой памятью� Операции на атомарных регистрах: read, write� Удобно программировать, все привыкли
Модель с передачей сообщений� Операции: send, onReceive� Похожа на то, как реально работает железо
Модели
Преимущества параллелизма
� Использование нескольких ядер/процессоров� Да и на 1 ядре тоже! (async I/O)
� Использование нескольких ядер/процессоров� Да и на 1 ядре тоже! (async I/O)
� Простота моделирования: фреймворк забирает сложность
Преимущества параллелизма
� Использование нескольких ядер/процессоров� Да и на 1 ядре тоже! (async I/O)
� Простота моделирования: фреймворк забирает сложность
� Упрощенная обработка асинхронных событий
Преимущества параллелизма
� Использование нескольких ядер/процессоров� Да и на 1 ядре тоже! (async I/O)
� Простота моделирования: фреймворк забирает сложность
� Упрощенная обработка асинхронных событий
� Более отзывчивые интерфейсы пользователя� Event Dispatch Thread (EDT), async calls
Преимущества параллелизма
Проблемы блокировок� Взаимоблокировки (Deadlocks)
� Взаимоблокировки (Deadlocks)� Инверсия приоритетов
Проблемы блокировок
� Взаимоблокировки (Deadlocks)� Инверсия приоритетов� Надежность
� вдруг владелец блокировки помрет?
Проблемы блокировок
� Взаимоблокировки (Deadlocks)� Инверсия приоритетов� Надежность
� вдруг владелец блокировки помрет?� Performance
� Параллелизма в критической секции нет!� Владелец блокировки может быть вытеснен планировщиком
Проблемы блокировок
Закон Амдалаα часть общего объема вычислений,
которую нельзя распараллелить
1-α часть, которую можно распараллелить
p количество потоков
Sp=𝟏
α#𝟏%α𝐩
α часть общего объема вычислений, которую нельзя распараллелить
1-α часть, которую можно распараллелить
p количество потоков
Закон Амдала
Фундаментальные законы природы� XIX век — законы Ньютона
Фундаментальные законы природы� XIX век — законы Ньютона
� XX век — закон Мура� тактовые частоты� число транзисторов
Фундаментальные законы природы� XIX век — законы Ньютона
� XX век — закон Мура� тактовые частоты� число транзисторов
� XXI век — закон Амдала
Фундаментальные законы природы� XIX век — законы Ньютона
� XX век — закон Мура� тактовые частоты� число транзисторов
� XXI век — закон Амдала
Нарушение закона влечет за собой дисциплинарную, гражданско-правовую, административную или уголовную ответственность
If-Modify-Write
volatile int value = 0;
Есть ли в этом коде проблемы в многопоточном окружении?
if (value == 0) {value = 42;
}
If-Modify-Write
volatile int value = 0;
Нет атомарностиif (value == 0) {
value = 42;}
Compare and Swap
int value = 0;
LOCKif (value == 0) {
value = 42;}
UNLOCK
Введем волшебную операцию
value.compareAndSet(0, 42);
int value = 0;
Симуляция CAS через synchronizedlong value;
synchronized long get() { return value;
}
synchronized long compareAndSwap(long expected, long newValue) {long oldValue = value;if (oldValue == expected) {
value = newValue;}return oldValue;
}
synchronized boolean compareAndSet(long expected, long newValue){return expected == compareAndSwap(expected, newValue);
}
Compare and Swap — Hardware Support
compare-and-swapCAS
load-link / store-conditionalLL/SC
cmpxchg ldrex/strex lwarx/stwcx
Atomics
AtomicReference• r.get()
• r.compareAndSet(v1, v2)
• ...
AtomicLong• i.get()
• i.compareAndSet(42, 43)
• i.incrementAndGet(1)
• i.getAndAdd(5)
• ...
Пример. Многопоточный счетчик
AtomicLong value = new AtomicLong();
long get() {return value.get();
}
void increment() {long v;do {
v = value.get();} while (!value.compareAndSet(v, v + 1));
}
Пример. Многопоточный счетчик
AtomicLong value = new AtomicLong();
long get() {return value.get();
}
void increment() {long v;do {
v = value.get();} while (!value.compareAndSet(v, v + 1));
}
Недостатки CAS
Contended CAS —> тонны бесполезных CPU-циклов
do {v = value.get();
} while (!value.compareAndSet(v, v + 1));
Написание быстрых и корректных алгоритмов на CAS требует экспертизы
class Node<E> {
final E item;
Node<E> next;
Node(E item) {this.item = item;
}
}
...
class Node<E> {
final E item;
Node<E> next;
Node(E item) {this.item = item;
}
}
E3
E1
E2
E3
E1
E2
top
E3
E1
E2
top
item1
Thread 1
E3
E1
E2
top
item1
Thread 1
E3
E1
E2
top
item2item1
Thread 1 Thread 2
E3
E1
E2
top
item2item1
Thread 1 Thread 2
E3
E1
E2
top
item2item1
Thread 1 Thread 2
void push(E item) {Node<E> newHead = new Node<>(item);Node<E> oldHead;do {
oldHead = top.get();newHead.next = oldHead;
} while (!top.compareAndSet(oldHead, newHead));}
AtomicReference<Node<E>> top;E3
E1
E2
top
void push(E item) {Node<E> newHead = new Node<>(item);Node<E> oldHead;do {
oldHead = top.get();newHead.next = oldHead;
} while (!top.compareAndSet(oldHead, newHead));}
AtomicReference<Node<E>> top;E3
E1
E2
item
top
void push(E item) {Node<E> newHead = new Node<>(item);Node<E> oldHead;do {
oldHead = top.get();newHead.next = oldHead;
} while (!top.compareAndSet(oldHead, newHead));}
E3
E1
E2
item
AtomicReference<Node<E>> top;top
void push(E item) {Node<E> newHead = new Node<>(item);Node<E> oldHead;do {
oldHead = top.get();newHead.next = oldHead;
} while (!top.compareAndSet(oldHead, newHead));}
E3
E1
E2
AtomicReference<Node<E>> top;
item
top
void push(E item) {Node<E> newHead = new Node<>(item);Node<E> oldHead;do {
oldHead = top.get();newHead.next = oldHead;
} while (!top.compareAndSet(oldHead, newHead));}
AtomicReference<Node<E>> top;E3
E1
E2
item
top
void push(E item) {Node<E> newHead = new Node<>(item);Node<E> oldHead;do {
oldHead = top.get();newHead.next = oldHead;
} while (!top.compareAndSet(oldHead, newHead));}
AtomicReference<Node<E>> top;E3
E1
E2
item
top
void push(E item) {Node<E> newHead = new Node<>(item);Node<E> oldHead;do {
oldHead = top.get();newHead.next = oldHead;
} while (!top.compareAndSet(oldHead, newHead));}
AtomicReference<Node<E>> top;E3
E1
E2
item
top
void push(E item) {Node<E> newHead = new Node<>(item);Node<E> oldHead;do {
oldHead = top.get();newHead.next = oldHead;
} while (!top.compareAndSet(oldHead, newHead));}
AtomicReference<Node<E>> top;E3
E1
E2
item
top
void push(E item) {Node<E> newHead = new Node<>(item);Node<E> oldHead;do {
oldHead = top.get();newHead.next = oldHead;
} while (!top.compareAndSet(oldHead, newHead));}
E3
E1
E2
AtomicReference<Node<E>> top;top
item
void push(E item) {Node<E> newHead = new Node<>(item);Node<E> oldHead;do {
oldHead = top.get();newHead.next = oldHead;
} while (!top.compareAndSet(oldHead, newHead));}
E3
E1
E2
AtomicReference<Node<E>> top;top
item
E pop() {Node<E> newHead;Node<E> oldHead;do {
oldHead = top.get();if (oldHead == null) return null;newHead = oldHead.next;
} while (!top.compareAndSet(oldHead, newHead));return oldHead.item;
}
E3
E1
E2
top
Michael and Scott, 1996https://www.research.ibm.com/people/m/michael/podc-1996.pdf
Потоки помогают друг другу
Неблокирующаяочередь
class LinkedQueue<E> {
static class Node<E> {final E item;final AtomicReference<Node<E>> next;
Node(E item, AtomicReference<Node<E>> next) {this.item = item;this.next = next;
}}
final Node<E> dummy = new Node<>(null, null);final AtomicReference<Node<E>> head = new AtomicReference<>(dummy);final AtomicReference<Node<E>> tail = new AtomicReference<>(dummy);
}
class LinkedQueue<E> {
static class Node<E> {final E item;final AtomicReference<Node<E>> next;
Node(E item, AtomicReference<Node<E>> next) {this.item = item;this.next = next;
}}
final Node<E> dummy = new Node<>(null, null);final AtomicReference<Node<E>> head = new AtomicReference<>(dummy);final AtomicReference<Node<E>> tail = new AtomicReference<>(dummy);
}
class LinkedQueue<E> {
private static class Node<E> {final E item;final AtomicReference<Node<E>> next;
Node(E item, AtomicReference<Node<E>> next) {this.item = item;this.next = next;
}}
final Node<E> dummy = new Node<>(null, null);final AtomicReference<Node<E>> head = new AtomicReference<>(dummy);final AtomicReference<Node<E>> tail = new AtomicReference<>(dummy);
}
tailhead
dummy 1 2
tailhead
dummy 1 2 3
tailhead
dummy 1 2 3
tailhead
dummy 1 2 3
public boolean put(E item) {Node<E> newNode = new Node<>(item, null);while (true) {
Node<E> currentTail = tail.get();Node<E> tailNext = currentTail.next.get();if (currentTail == tail.get()) {
if (tailNext != null) {tail.compareAndSet(currentTail, tailNext);
} else {if (currentTail.next.compareAndSet(null, newNode)) {
tail.compareAndSet(currentTail, newNode);return true;
}}
}}
}
tail
head
dummy 1 2
public boolean put(E item) {Node<E> newNode = new Node<>(item, null);while (true) {
Node<E> currentTail = tail.get();Node<E> tailNext = currentTail.next.get();if (currentTail == tail.get()) {
if (tailNext != null) {tail.compareAndSet(currentTail, tailNext);
} else {if (currentTail.next.compareAndSet(null, newNode)) {
tail.compareAndSet(currentTail, newNode);return true;
}}
}}
}
tail
head
dummy 1 2 item
public boolean put(E item) {Node<E> newNode = new Node<>(item, null); while (true) {
Node<E> currentTail = tail.get();Node<E> tailNext = currentTail.next.get();if (currentTail == tail.get()) {
if (tailNext != null) {tail.compareAndSet(currentTail, tailNext);
} else {if (currentTail.next.compareAndSet(null, newNode)) {
tail.compareAndSet(currentTail, newNode);return true;
}}
}}
}
tail
head
dummy 1 2 item
public boolean put(E item) {Node<E> newNode = new Node<>(item, null); while (true) {
Node<E> currentTail = tail.get(); Node<E> tailNext = currentTail.next.get();if (currentTail == tail.get()) {
if (tailNext != null) {tail.compareAndSet(currentTail, tailNext);
} else {if (currentTail.next.compareAndSet(null, newNode)) {
tail.compareAndSet(currentTail, newNode);return true;
}}
}}
}
tail
head
dummy 1 2 item
public boolean put(E item) {Node<E> newNode = new Node<>(item, null); while (true) {
Node<E> currentTail = tail.get(); Node<E> tailNext = currentTail.next.get(); if (currentTail == tail.get()) {
if (tailNext != null) {tail.compareAndSet(currentTail, tailNext);
} else {if (currentTail.next.compareAndSet(null, newNode)) {
tail.compareAndSet(currentTail, newNode);return true;
}}
}}
}
tail
head
dummy 1 2 item
public boolean put(E item) {Node<E> newNode = new Node<>(item, null); while (true) {
Node<E> currentTail = tail.get(); Node<E> tailNext = currentTail.next.get(); // tailNext ?= nullif (currentTail == tail.get()) {
if (tailNext != null) {tail.compareAndSet(currentTail, tailNext);
} else {if (currentTail.next.compareAndSet(null, newNode)) {
tail.compareAndSet(currentTail, newNode);return true;
}}
}}
}
tail
head
dummy 1 2 item
public boolean put(E item) {Node<E> newNode = new Node<>(item, null); while (true) {
Node<E> currentTail = tail.get(); Node<E> tailNext = currentTail.next.get(); if (currentTail == tail.get()) {
if (tailNext != null) {tail.compareAndSet(currentTail, tailNext);
} else {if (currentTail.next.compareAndSet(null, newNode)) {
tail.compareAndSet(currentTail, newNode);return true;
}}
}}
}
tail
head
dummy 1 2 item
public boolean put(E item) {Node<E> newNode = new Node<>(item, null); while (true) {
Node<E> currentTail = tail.get(); Node<E> tailNext = currentTail.next.get(); if (currentTail == tail.get()) {
if (tailNext != null) {tail.compareAndSet(currentTail, tailNext);
} else {if (currentTail.next.compareAndSet(null, newNode)) {
tail.compareAndSet(currentTail, newNode);return true;
}}
}}
}
tail
head
dummy 1 2 item
public boolean put(E item) {Node<E> newNode = new Node<>(item, null); while (true) {
Node<E> currentTail = tail.get(); Node<E> tailNext = currentTail.next.get(); if (currentTail == tail.get()) {
if (tailNext != null) {tail.compareAndSet(currentTail, tailNext);
} else {if (currentTail.next.compareAndSet(null, newNode)) {
tail.compareAndSet(currentTail, newNode);return true;
}}
}}
}
tail
head
dummy 1 2 item
public boolean put(E item) {Node<E> newNode = new Node<>(item, null); while (true) {
Node<E> currentTail = tail.get(); Node<E> tailNext = currentTail.next.get(); if (currentTail == tail.get()) {
if (tailNext != null) {tail.compareAndSet(currentTail, tailNext);
} else {if (currentTail.next.compareAndSet(null, newNode)) {
tail.compareAndSet(currentTail, newNode);return true;
}}
}}
}
tail
head
dummy 1 2 item
public boolean put(E item) {Node<E> newNode = new Node<>(item, null); while (true) {
Node<E> currentTail = tail.get(); Node<E> tailNext = currentTail.next.get(); if (currentTail == tail.get()) {
if (tailNext != null) { // tailNext != nulltail.compareAndSet(currentTail, tailNext);
} else {if (currentTail.next.compareAndSet(null, newNode)) {
tail.compareAndSet(currentTail, newNode);return true;
}}
}}
}
tail
head
dummy 1 2 item
public boolean put(E item) {Node<E> newNode = new Node<>(item, null); while (true) {
Node<E> currentTail = tail.get(); Node<E> tailNext = currentTail.next.get(); if (currentTail == tail.get()) {
if (tailNext != null) { // tailNext != nulltail.compareAndSet(currentTail, tailNext);
} else {if (currentTail.next.compareAndSet(null, newNode)) {
tail.compareAndSet(currentTail, newNode);return true;
}}
}}
}
tail
head
dummy 1 2 item
public boolean put(E item) {Node<E> newNode = new Node<>(item, null); while (true) {
Node<E> currentTail = tail.get(); Node<E> tailNext = currentTail.next.get(); if (currentTail == tail.get()) {
if (tailNext != null) {tail.compareAndSet(currentTail, tailNext);
} else {if (currentTail.next.compareAndSet(null, newNode)) {
tail.compareAndSet(currentTail, newNode);return true;
}}
}}
}
tail
head
dummy 1 2 item
public boolean put(E item) {Node<E> newNode = new Node<>(item, null); while (true) {
Node<E> currentTail = tail.get(); Node<E> tailNext = currentTail.next.get(); if (currentTail == tail.get()) {
if (tailNext != null) { tail.compareAndSet(currentTail, tailNext);
} else {if (currentTail.next.compareAndSet(null, newNode)) {
tail.compareAndSet(currentTail, newNode);return true;
}}
}}
}
tail
head
dummy 1 2 item
public boolean put(E item) {Node<E> newNode = new Node<>(item, null); while (true) {
Node<E> currentTail = tail.get(); Node<E> tailNext = currentTail.next.get(); if (currentTail == tail.get()) {
if (tailNext != null) {tail.compareAndSet(currentTail, tailNext);
} else { // tailNext == null if (currentTail.next.compareAndSet(null, newNode)) {
tail.compareAndSet(currentTail, newNode);return true;
}}
}}
}
tail
head
dummy 1 2 item
public boolean put(E item) {Node<E> newNode = new Node<>(item, null); while (true) {
Node<E> currentTail = tail.get(); Node<E> tailNext = currentTail.next.get(); if (currentTail == tail.get()) {
if (tailNext != null) {tail.compareAndSet(currentTail, tailNext);
} else { // tailNext == null if (currentTail.next.compareAndSet(null, newNode)) {
tail.compareAndSet(currentTail, newNode);return true;
}}
}}
}
tail
head
dummy 1 2 item
public boolean put(E item) {Node<E> newNode = new Node<>(item, null); while (true) {
Node<E> currentTail = tail.get(); Node<E> tailNext = currentTail.next.get(); if (currentTail == tail.get()) {
if (tailNext != null) {tail.compareAndSet(currentTail, tailNext);
} else { // tailNext == null if (currentTail.next.compareAndSet(null, newNode)) {
tail.compareAndSet(currentTail, newNode);return true;
}}
}}
}
tail
head
dummy 1 2 item
public boolean put(E item) {Node<E> newNode = new Node<>(item, null); while (true) {
Node<E> currentTail = tail.get(); Node<E> tailNext = currentTail.next.get(); if (currentTail == tail.get()) {
if (tailNext != null) {tail.compareAndSet(currentTail, tailNext);
} else { // tailNext == null if (currentTail.next.compareAndSet(null, newNode)) {
tail.compareAndSet(currentTail, newNode);return true;
}}
}}
}
tail
head
dummy 1 2 item
public boolean put(E item) {Node<E> newNode = new Node<>(item, null); while (true) {
Node<E> currentTail = tail.get(); Node<E> tailNext = currentTail.next.get(); if (currentTail == tail.get()) {
if (tailNext != null) {tail.compareAndSet(currentTail, tailNext);
} else { // tailNext == null if (currentTail.next.compareAndSet(null, newNode)) {
tail.compareAndSet(currentTail, newNode);return true;
}}
}}
}
tail
head
dummy 1 2 item
public boolean put(E item) {Node<E> newNode = new Node<>(item, null); while (true) {
Node<E> currentTail = tail.get(); Node<E> tailNext = currentTail.next.get(); if (currentTail == tail.get()) {
if (tailNext != null) {tail.compareAndSet(currentTail, tailNext);
} else { // tailNext == null if (currentTail.next.compareAndSet(null, newNode)) {
tail.compareAndSet(currentTail, newNode);return true;
}}
}}
}
tail
head
dummy 1 2 item
public boolean put(E item) {Node<E> newNode = new Node<>(item, null); while (true) {
Node<E> currentTail = tail.get(); Node<E> tailNext = currentTail.next.get(); if (currentTail == tail.get()) {
if (tailNext != null) {tail.compareAndSet(currentTail, tailNext);
} else { // tailNext == null if (currentTail.next.compareAndSet(null, newNode)) {
tail.compareAndSet(currentTail, newNode);return true;
}}
}}
}
tail
head
dummy 1 2 item
public boolean put(E item) {Node<E> newNode = new Node<>(item, null); while (true) {
Node<E> currentTail = tail.get(); Node<E> tailNext = currentTail.next.get(); if (currentTail == tail.get()) {
if (tailNext != null) {tail.compareAndSet(currentTail, tailNext);
} else { // tailNext == null if (currentTail.next.compareAndSet(null, newNode)) {
tail.compareAndSet(currentTail, newNode); // truereturn true;
}}
}}
}
tail
head
dummy 1 2 item
public boolean put(E item) {Node<E> newNode = new Node<>(item, null); while (true) {
Node<E> currentTail = tail.get(); Node<E> tailNext = currentTail.next.get(); if (currentTail == tail.get()) {
if (tailNext != null) {tail.compareAndSet(currentTail, tailNext);
} else { // tailNext == null if (currentTail.next.compareAndSet(null, newNode)) {
tail.compareAndSet(currentTail, newNode); // truereturn true;
}}
}}
}
tail
head
dummy 1 2 item
public boolean put(E item) {Node<E> newNode = new Node<>(item, null); while (true) {
Node<E> currentTail = tail.get(); Node<E> tailNext = currentTail.next.get(); if (currentTail == tail.get()) {
if (tailNext != null) {tail.compareAndSet(currentTail, tailNext);
} else { // tailNext == null if (currentTail.next.compareAndSet(null, newNode)) {
tail.compareAndSet(currentTail, newNode);return true;
}}
}}
}
tail
head
dummy 1 2 item
public boolean put(E item) {Node<E> newNode = new Node<>(item, null); while (true) {
Node<E> currentTail = tail.get(); Node<E> tailNext = currentTail.next.get(); if (currentTail == tail.get()) {
if (tailNext != null) {tail.compareAndSet(currentTail, tailNext);
} else { // tailNext == null if (currentTail.next.compareAndSet(null, newNode)) {
tail.compareAndSet(currentTail, newNode); // falsereturn true;
}}
}}
}
tail
head
dummy 1 2 item
public boolean put(E item) {Node<E> newNode = new Node<>(item, null); while (true) {
Node<E> currentTail = tail.get(); Node<E> tailNext = currentTail.next.get(); if (currentTail == tail.get()) {
if (tailNext != null) {tail.compareAndSet(currentTail, tailNext);
} else { // tailNext == null if (currentTail.next.compareAndSet(null, newNode)) {
tail.compareAndSet(currentTail, newNode); // falsereturn true;
}}
}}
}
tail
head
dummy 1 2 item
public boolean put(E item) {Node<E> newNode = new Node<>(item, null); while (true) {
Node<E> currentTail = tail.get(); Node<E> tailNext = currentTail.next.get(); if (currentTail == tail.get()) {
if (tailNext != null) {tail.compareAndSet(currentTail, tailNext);
} else { // tailNext == null if (currentTail.next.compareAndSet(null, newNode)) {
tail.compareAndSet(currentTail, newNode); // falsereturn true;
}}
}}
}
tail
head
dummy 1 2 item
public boolean put(E item) {Node<E> newNode = new Node<>(item, null); while (true) {
Node<E> currentTail = tail.get(); Node<E> tailNext = currentTail.next.get(); if (currentTail == tail.get()) {
if (tailNext != null) {tail.compareAndSet(currentTail, tailNext);
} else { // tailNext == null if (currentTail.next.compareAndSet(null, newNode)) {
tail.compareAndSet(currentTail, newNode); // falsereturn true;
}}
}}
}
tail
head
dummy 1 2 item
Что получилось
public boolean put(E item) {Node<E> newNode = new Node<>(item, null);while (true) {
Node<E> currentTail = tail.get();Node<E> tailNext = currentTail.next.get();if (currentTail == tail.get()) {
if (tailNext != null) {tail.compareAndSet(currentTail, tailNext);
} else {if (currentTail.next.compareAndSet(null, newNode)) {
tail.compareAndSet(currentTail, newNode);return true;
}}
}}
}
public boolean put(E item) {Node<E> newNode = new Node<>(item, null);while (true) {
Node<E> currentTail = tail.get();Node<E> tailNext = currentTail.next.get();if (currentTail == tail.get()) {
if (tailNext != null) {tail.compareAndSet(currentTail, tailNext);
} else {if (currentTail.next.compareAndSet(null, newNode)) {
tail.compareAndSet(currentTail, newNode);return true;
}}
}}
} АД И ЧЕРТИ (ЗДЕСЬ ДОЛЖНА БЫТЬ КАРТИНКА)
ArrayBlockingQueue
ArrayBlockingQueue
0 1 2 3 4 N-1...
void put(E e) throws InterruptedException {checkNotNull(e);final ReentrantLock lock = this.lock;lock.lockInterruptibly();try {
while (count == items.length)notFull.await();
final Object[] items = this.items;items[putIndex] = x;if (++putIndex == items.length)
putIndex = 0;count++;notEmpty.signal();
} finally {lock.unlock();
}}
Как put() сделан в ArrayBlockingQueue
void put(E e) throws InterruptedException {checkNotNull(e);final ReentrantLock lock = this.lock;lock.lockInterruptibly();try {
while (count == items.length)notFull.await();
final Object[] items = this.items;items[putIndex] = x;if (++putIndex == items.length)
putIndex = 0;count++;notEmpty.signal();
} finally {lock.unlock();
}}
Как put() сделан в ArrayBlockingQueue
void put(E e) throws InterruptedException {checkNotNull(e);final ReentrantLock lock = this.lock;lock.lockInterruptibly();try {
while (count == items.length)notFull.await();
final Object[] items = this.items;items[putIndex] = x;if (++putIndex == items.length)
putIndex = 0;count++;notEmpty.signal();
} finally {lock.unlock();
}}
Как put() сделан в ArrayBlockingQueue
void put(E e) throws InterruptedException {checkNotNull(e);final ReentrantLock lock = this.lock;lock.lockInterruptibly();try {
while (count == items.length)notFull.await();
final Object[] items = this.items;items[putIndex] = x;if (++putIndex == items.length)
putIndex = 0;count++;notEmpty.signal();
} finally {lock.unlock();
}}
Как put() сделан в ArrayBlockingQueue
void put(E e) throws InterruptedException {checkNotNull(e);final ReentrantLock lock = this.lock;lock.lockInterruptibly();try {
while (count == items.length)notFull.await();
final Object[] items = this.items;items[putIndex] = x;if (++putIndex == items.length)
putIndex = 0;count++;notEmpty.signal();
} finally {lock.unlock();
}}
Как put() сделан в ArrayBlockingQueue
Выводы
� Неблокирующие алгоритмы могут быть очень сложными� корректность написанного может быть не очевидна� такие решения очень сложно поддерживать� самописные решения кишат багами
� На практике такие решения используют редко
� Если ваши ограничения позволяют использовать блокировки, не заморачивайтесь с lock-free
Выводы
� Неблокирующие алгоритмы могут быть очень сложными� корректность написанного может быть не очевидна� такие решения очень сложно поддерживать� самописные решения кишат багами
� На практике такие решения используют редко
� Если ваши ограничения позволяют использовать блокировки, не заморачивайтесь с lock-free
Выводы
Модификации
Ladan-Mozes, Shavit, 2004, 2008Идея:избавитьсяотвторогоCAS
OptimisticApproach
http://people.csail.mit.edu/edya/publications/OptimisticFIFOQueue-journal.pdf
Hoffman, Shalev, Shavit, 2007
BasketsQueue
http://people.csail.mit.edu/shanir/publications/Baskets%20Queue.pdf
� Есть выигрыш в производительности по сравнению с обычной неблокирующей очередью
� за это мы платим потерей FIFO-свойства
� в реальной жизни «честный» FIFO нужен не всегда� если вам нужно больше перфоманса, им можно пожертвовать.
Baskets Queue
Материалы
Литература
Материалы
• Nitsan Wakart — http://psy-lob-saw.blogspot.com/• АлексейШипилёв — https://shipilev.net/• МаксимХижинский — https://habrahabr.ru/post/219201/
Вопросы и ответы