JavaRush /Java блог /Random UA /Приклад SynchronousQueue в Java - рішення задачі Виробник...
profeg
18 рівень

Приклад SynchronousQueue в Java - рішення задачі Виробник Споживач

Стаття з групи Random UA
Приклад SynchronousQueue в Java - рішення задачі Виробник Споживач
SynchronousQueue - це спеціальний тип BlockingQueue, в якому кожна операція insert повинна чекати відповідну команду remove в іншій нитці, і навпаки. Коли ви викликаєте метод put() у SynchronousQueue, він блокується доти, доки інша нитка не забере цей елемент із нього. Відповідно, якщо інша нитка намагається видалити елемент із нього, а елемента там немає, то ця нитка блокується доти, доки інша нитка не покладе елемент у чергу. Можна уявити SynchronousQueue як спортсмена ( нитка ), що біжить з олімпійським факелом, він біжить з факелом (об'єктом який передається) і передає його іншому спортсмену, який очікує з іншого боку. Якщо ви звернете увагу на назву, то зрозумієте, що SynchronousQueue так названо не безпідставно, вінпередає дані синхронізовано в іншу нитку ; він чекає поки хтось забере дані, замість просто покласти їх і завершитися (асинхронна операція). Якщо ви знайомі з CSP та Ada, то ви знаєте, що синхронізовані черги схожі на зустріч потоків. Вони добре підходять для конструкцій передачі управління, в яких об'єкт запущений в одній нитці повинен синхронізуватися з об'єктом в іншій нитці, щоб передати йому якусь інформацію, подію або завдання. У раніше вивчених підручниках з багато-нітевого програмування ми вивчали як вирішити задачу виробник-споживач, використовуючи методи wait і notify , і BlockingQueue . Зараз ми дізнаємося , як застосувати виробник-споживач патерн використовуючи SynchronousQueue.Цей клас додатково підтримує чесну поведінку для впорядкованості очікування ниток виробника та споживача. За умовчанням ця впорядкованість не гарантована. Однак черги, створені з чесними властивостями, роблять гарантованим доступ для ниток у черговості FIFO (Firs In First Out – хто Перший Прийшов, той Перший Вийшов).
Виробник споживача використовуючи SynchronousQueue в Java.
Приклад SynchronousQueue в Java - розв'язання задачі Виробник Споживач - 1 Як я говорив вище, немає нічого кращого, ніж завдання виробника-споживача для розуміння між-ниткової взаємодіїу будь-якій мові програмування. У цій проблемі одна нитка виступає як виробник, який виробляє події та завдання, а інша нитка виступає споживачем цього. Загальний буфер використовується передачі даних від виробника до споживача. Складність розв'язання цього завдання приходить у крайніх випадках, наприклад, коли виробник змушений чекати т.к. буфер заповнений чи споживач змушений чекати, т.к. буфер порожній. Це легко вирішувалося, т.к. блокуюча черга надавала як буфер для зберігання даних, а й управління потоком, блокуючи нитку викликає put() метод (Виробник) якщо буфер заповнений, і блокуючи нитку викликає таке() метод (Споживач) якщо буфер порожній. Зараз ми вирішимо це саме завдання використовуючи SynchronousQueue, спеціальний вид паралельних колекційз нульовою ємністю. У наступному прикладі у нас є дві нитки , які називаються PRODUCER і CONSUMER (завжди давайте імена ниткам, це дуже хороший стиль багато-ниткового програмування). Перша нитка розміщує рахунок у грі, а друга нитка його споживає. Рахунок у грі ніщо інше як об'єкт типу String. Але якщо ви запустите програму з іншим типом, ви не помітите жодної різниці. Щоб зрозуміти як SynchronousQueue працює, і як вирішувати завдання виробник-споживач вам потрібно: або запустити програму налагодження (debug) в середовищі Eclipse, або просто запустити нитку виробника закоментувавши consumer.start(); якщо нитка споживача не запущена, то нитка виробника буде заблокована на queue.put(event); якщо запущена, ви не зможете бачити як виробник [PRODUCER] публікує подію :FOUR. Це відбувається т.к. специфічна поведінка SynchronousQueue, яка гарантує, що нитка розміщує дані буде заблокована доти, поки інша нитка не забере ці дані, і навпаки. Ви можете протестувати частину коду, що залишилася, закоментувавши producer.start(); і запускаючи лише нитку споживача. Якщо ви уважно вивчите, що програма виводить, то помітите, що порядок виводу зворотний. Виглядає наче нитка [CONSUMER] забрала дані ще до того, як нитка [PRODUCER] import java.util.concurrent.SynchronousQueue; /** * Java Program to solve Producer Consumer problem using SynchronousQueue. A * call to put() will block until there is a corresponding thread to take() that * element. * * @author Javin Paul */ public class SynchronousQueueDemo{ public static void main(String args[]) { final SynchronousQueue queue = new SynchronousQueue (); Thread producer = new Thread("PRODUCER") { public void run() { String event = "FOUR"; try { queue.put(event); // thread will block here System.out.printf("[%s] published event : %s %n", Thread .currentThread() .getName(), event); } catch (InterruptedException e) { e.printStackTrace(); } } }; producer.start(); // starting publisher thread Thread consumer = new Thread("CONSUMER") { public void run() { try { String event = queue.take(); // thread will block here System.out.printf("[%s] consumed event : %s %n", Thread .currentThread() .getName(), event); } catch (InterruptedException e) { e.printStackTrace(); } } }; consumer.start(); // starting consumer thread } } Output: [CONSUMER] consumed event : FOUR [PRODUCER] published event : FOUR зробила їх. Це сталося через те, що SynchronousQueue за замовчуванням не гарантує черговості. Але вона має правила чесності, які встановлюють доступ до ниток у порядку FIFO. Ви можете включати ці правила передаючи true в перевантажений конструктор SynchronousQueue наприклад: new SynchronousQueue(boolean fair).
Що потрібно запам'ятати про SynchronousQueue в Java.

Тут кілька важливих властивостей цього спеціального типу черги, що блокується в Java. Дуже корисно передавати дані з однієї нитки до іншої синхронізовано. Ця черга не має обсягу і заблокована доти, доки її не звільнить інша нитка.

  1. SynchronousQueue блокується, і поки одна нитка не буде готова взяти дані, інша буде намагатися покласти дані.
  2. SynchronousQueue не має обсягу. Тобто, в ній не містяться дані.
  3. SynchronousQueue використовується для реалізації стратегії черговості прямої передачі управління, де нитка передає управління чекаючою нитки, або створює нову якщо це дозволено, інакше управління не передається.
  4. Ця черга не пропускає null-дані. Спроба додати елемент null кине NullPointerException .
  5. Якщо використовувати інші методи з колекції (наприклад, contains), SynchronousQueue поводиться як порожня колекція.
  6. Ви не зможете використовувати метод peek у SynchronousQueue, тому що елемент існує тільки тоді, коли ви намагаєтеся його видалити; так само ви не зможете вставляти елементи (використовуючи будь-який метод), поки інша нитка не намагається його видалити.
  7. Ви не зможете використати iterator для SynchronousQueue, т.к. у ній немає елементів.
  8. SynchronousQueue може створюватися з чесними правилами, коли гарантується доступ до ниток у порядку FIFO.
Мабуть, це все про SynchronousQueue в Java. Ми розглянули деякі особливі можливості цієї багато-ниткової колекції, і навчабося вирішувати класичне завдання виробник-споживач, використовуючи SynchronousQueue в Java. Між іншим, називати її Чергою не зовсім правильно, т.к. вона не містить елементів. Виклик методу put() не завершиться до того часу, поки інша нитка не викличе метод take(). Правильніше представляти її як місце зустрічі ниток, де вони діляться об'єктом. Іншими словами, це утиліта синхронізованої передачі об'єктів в Java, можливо більш безпечна альтернатива методу з використанням wait і notify .
Коментарі
ЩОБ ПОДИВИТИСЯ ВСІ КОМЕНТАРІ АБО ЗАЛИШИТИ КОМЕНТАР,
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ