Ce diaporama a bien été signalé.
Nous utilisons votre profil LinkedIn et vos données d’activité pour vous proposer des publicités personnalisées et pertinentes. Vous pouvez changer vos préférences de publicités à tout moment.
Prochain SlideShare
What to Upload to SlideShare
Suivant
Télécharger pour lire hors ligne et voir en mode plein écran

Partager

How threads help each other

Télécharger pour lire hors ligne

Introduction to non-blocking synchronization, non-blocking stack, non-blocking MS Queue

Livres associés

Gratuit avec un essai de 30 jours de Scribd

Tout voir

How threads help each other

  1. 1. Как потоки помогают друг другу Алексей Федоров, JUG.ru
  2. 2. Алексей Федоров about.me/23derevo
  3. 3. Java-конференции JUG.ru Group Санкт-Петербург 3-4 ноября 2017 Москва 6-7 апреля 2018
  4. 4. — Программирование — Алгоритмы — Многопоточность Про что этот доклад
  5. 5. Много интересных докладов в других залах
  6. 6. Новичкам в области многопоточности Sorry Перейдите в другой зал Про что этот доклад
  7. 7. Новичкам в области многопоточности Sorry Перейдите в другой зал Новичкам в неблокирующей синхронизации Короткое введение Про что этот доклад
  8. 8. Новичкам в области многопоточности Sorry Перейдите в другой зал Новичкам в неблокирующей синхронизации Короткое введение Продвинутым многопоточным программистам Поговорим о неблокирующей синхронизации Про что этот доклад
  9. 9. Модели
  10. 10. Модели Модель с разделяемой памятью — Операции на атомарных регистрах: read, write — Удобно программировать, все привыкли
  11. 11. Модель с разделяемой памятью — Операции на атомарных регистрах: read, write — Удобно программировать, все привыкли Модель с передачей сообщений — Операции: send, onReceive — Похожа на то, как реально работает железо Модели
  12. 12. Преимущества параллелизма — Использование нескольких ядер/процессоров — Да и на 1 ядре тоже! (async I/O)
  13. 13. — Использование нескольких ядер/процессоров — Да и на 1 ядре тоже! (async I/O) — Простота моделирования: фреймворк забирает сложность Преимущества параллелизма
  14. 14. — Использование нескольких ядер/процессоров — Да и на 1 ядре тоже! (async I/O) — Простота моделирования: фреймворк забирает сложность — Упрощенная обработка асинхронных событий Преимущества параллелизма
  15. 15. — Использование нескольких ядер/процессоров — Да и на 1 ядре тоже! (async I/O) — Простота моделирования: фреймворк забирает сложность — Упрощенная обработка асинхронных событий — Более отзывчивые интерфейсы пользователя — Event Dispatch Thread (EDT), async calls Преимущества параллелизма
  16. 16. Проблемы блокировок — Взаимоблокировки (Deadlocks)
  17. 17. — Взаимоблокировки (Deadlocks) — Инверсия приоритетов Проблемы блокировок
  18. 18. — Взаимоблокировки (Deadlocks) — Инверсия приоритетов — Надежность — вдруг владелец блокировки помрет? Проблемы блокировок
  19. 19. — Взаимоблокировки (Deadlocks) — Инверсия приоритетов — Надежность — вдруг владелец блокировки помрет? — Performance — Параллелизма в критической секции нет! — Владелец блокировки может быть вытеснен планировщиком Проблемы блокировок
  20. 20. Закон Амдала α часть общего объема вычислений, которую нельзя распараллелить 1-α часть, которую можно распараллелить p количество потоков
  21. 21. Sp= 𝟏 α# 𝟏%α 𝐩 α часть общего объема вычислений, которую нельзя распараллелить 1-α часть, которую можно распараллелить p количество потоков Закон Амдала
  22. 22. Фундаментальные законы природы — XIX век — законы Ньютона
  23. 23. Фундаментальные законы природы — XIX век — законы Ньютона — XX век — закон Мура — тактовые частоты — число транзисторов
  24. 24. Фундаментальные законы природы — XIX век — законы Ньютона — XX век — закон Мура — тактовые частоты — число транзисторов — XXI век — закон Амдала
  25. 25. Фундаментальные законы природы — XIX век — законы Ньютона — XX век — закон Мура — тактовые частоты — число транзисторов — XXI век — закон Амдала Нарушение закона влечет за собой дисциплинарную, гражданско-правовую, административную или уголовную ответственность
  26. 26. If-Modify-Write volatile int value = 0; Есть ли в этом коде проблемы в многопоточном окружении? if (value == 0) { value = 42; }
  27. 27. If-Modify-Write volatile int value = 0; Нет атомарности if (value == 0) { value = 42; }
  28. 28. Compare and Swap int value = 0; LOCK if (value == 0) { value = 42; } UNLOCK
  29. 29. Введем волшебную операцию value.compareAndSet(0, 42); int value = 0;
  30. 30. Симуляция CAS через synchronized long 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); }
  31. 31. Compare and Swap — Hardware Support compare-and-swap CAS load-link / store-conditional LL/SC cmpxchg ldrex/strex lwarx/stwcx
  32. 32. Atomics AtomicReference • r.get() • r.compareAndSet(v1, v2) • ... AtomicLong • i.get() • i.compareAndSet(42, 43) • i.incrementAndGet(1) • i.getAndAdd(5) • ...
  33. 33. Пример. Многопоточный счетчик AtomicLong value = new AtomicLong(); long get() { return value.get(); } void increment() { long v; do { v = value.get(); } while (!value.compareAndSet(v, v + 1)); }
  34. 34. Пример. Многопоточный счетчик AtomicLong value = new AtomicLong(); long get() { return value.get(); } void increment() { long v; do { v = value.get(); } while (!value.compareAndSet(v, v + 1)); }
  35. 35. Недостатки CAS Contended CAS —> тонны бесполезных CPU-циклов do { v = value.get(); } while (!value.compareAndSet(v, v + 1)); Написание быстрых и корректных алгоритмов на CAS требует экспертизы
  36. 36. class Node<E> { final E item; Node<E> next; Node(E item) { this.item = item; } } ...
  37. 37. class Node<E> { final E item; Node<E> next; Node(E item) { this.item = item; } } E3 E1 E2
  38. 38. E3 E1 E2 top
  39. 39. E3 E1 E2 top item1 Thread 1
  40. 40. E3 E1 E2 top item1 Thread 1
  41. 41. E3 E1 E2 top item2item1 Thread 1 Thread 2
  42. 42. E3 E1 E2 top item2item1 Thread 1 Thread 2
  43. 43. E3 E1 E2 top item2item1 Thread 1 Thread 2
  44. 44. 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
  45. 45. 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
  46. 46. 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
  47. 47. 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
  48. 48. 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
  49. 49. 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
  50. 50. 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
  51. 51. 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
  52. 52. 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
  53. 53. 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
  54. 54. 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
  55. 55. Michael and Scott, 1996 https://www.research.ibm.com/people/m/michael/podc-1996.pdf Потоки помогают друг другу Неблокирующая очередь
  56. 56. 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); }
  57. 57. 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); }
  58. 58. 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); }
  59. 59. tailhead dummy 1 2
  60. 60. tailhead dummy 1 2 3
  61. 61. tailhead dummy 1 2 3
  62. 62. tailhead dummy 1 2 3
  63. 63. 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
  64. 64. 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
  65. 65. 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
  66. 66. 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
  67. 67. 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
  68. 68. 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 ?= null 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
  69. 69. 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
  70. 70. 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
  71. 71. 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
  72. 72. 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
  73. 73. 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 != null tail.compareAndSet(currentTail, tailNext); } else { if (currentTail.next.compareAndSet(null, newNode)) { tail.compareAndSet(currentTail, newNode); return true; } } } } } tail head dummy 1 2 item
  74. 74. 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 != null tail.compareAndSet(currentTail, tailNext); } else { if (currentTail.next.compareAndSet(null, newNode)) { tail.compareAndSet(currentTail, newNode); return true; } } } } } tail head dummy 1 2 item
  75. 75. 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
  76. 76. 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
  77. 77. 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
  78. 78. 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
  79. 79. 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
  80. 80. 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
  81. 81. 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
  82. 82. 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
  83. 83. 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
  84. 84. 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); // true return true; } } } } } tail head dummy 1 2 item
  85. 85. 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); // true return true; } } } } } tail head dummy 1 2 item
  86. 86. 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
  87. 87. 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); // false return true; } } } } } tail head dummy 1 2 item
  88. 88. 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); // false return true; } } } } } tail head dummy 1 2 item
  89. 89. 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); // false return true; } } } } } tail head dummy 1 2 item
  90. 90. 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); // false return true; } } } } } tail head dummy 1 2 item
  91. 91. Что получилось
  92. 92. 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; } } } } }
  93. 93. 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; } } } } } АД И ЧЕРТИ (ЗДЕСЬ ДОЛЖНА БЫТЬ КАРТИНКА)
  94. 94. ArrayBlockingQueue
  95. 95. ArrayBlockingQueue 0 1 2 3 4 N-1 ...
  96. 96. 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
  97. 97. 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
  98. 98. 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
  99. 99. 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
  100. 100. 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
  101. 101. Выводы
  102. 102. — Неблокирующие алгоритмы могут быть очень сложными — корректность написанного может быть не очевидна — такие решения очень сложно поддерживать — самописные решения кишат багами — На практике такие решения используют редко — Если ваши ограничения позволяют использовать блокировки, не заморачивайтесь с lock-free Выводы
  103. 103. — Неблокирующие алгоритмы могут быть очень сложными — корректность написанного может быть не очевидна — такие решения очень сложно поддерживать — самописные решения кишат багами — На практике такие решения используют редко — Если ваши ограничения позволяют использовать блокировки, не заморачивайтесь с lock-free Выводы
  104. 104. Модификации
  105. 105. Ladan-Mozes, Shavit, 2004, 2008 Идея: избавиться от второго CAS Optimistic Approach http://people.csail.mit.edu/edya/publications/OptimisticFIFOQueue-journal.pdf
  106. 106. Hoffman, Shalev, Shavit, 2007 Baskets Queue http://people.csail.mit.edu/shanir/publications/Baskets%20Queue.pdf
  107. 107. — Есть выигрыш в производительности по сравнению с обычной неблокирующей очередью — за это мы платим потерей FIFO-свойства — в реальной жизни «честный» FIFO нужен не всегда — если вам нужно больше перфоманса, им можно пожертвовать. Baskets Queue
  108. 108. Материалы
  109. 109. Литература
  110. 110. Материалы • Nitsan Wakart — http://psy-lob-saw.blogspot.com/ • Алексей Шипилёв — https://shipilev.net/ • Максим Хижинский — https://habrahabr.ru/post/219201/
  111. 111. Вопросы и ответы
  • bores

    Sep. 6, 2017
  • anatolyromanov3

    May. 30, 2017

Introduction to non-blocking synchronization, non-blocking stack, non-blocking MS Queue

Vues

Nombre de vues

1 100

Sur Slideshare

0

À partir des intégrations

0

Nombre d'intégrations

355

Actions

Téléchargements

10

Partages

0

Commentaires

0

Mentions J'aime

2

×