JavaRush /Blog Java /Random-PL /Przykład SynchronousQueue w Javie - rozwiązanie problemu ...
profeg
Poziom 18

Przykład SynchronousQueue w Javie - rozwiązanie problemu Producent Konsument

Opublikowano w grupie Random-PL
Przykład SynchronousQueue w Javie - rozwiązanie problemu Producent Konsument
SynchronousQueue to specjalny typ BlockingQueue, w którym każda operacja wstawiania musi czekać na odpowiednie polecenie usunięcia w innym wątku i odwrotnie. Kiedy wywołasz metodę put() w kolejce SynchronousQueue, zostanie ona zablokowana do czasu, aż inny wątek pobierze z niej ten element. Odpowiednio, jeśli inny wątek spróbuje usunąć z niego element, a elementu tam nie ma, wówczas ten wątek blokuje się , dopóki inny wątek nie umieści elementu w kolejce. Można sobie wyobrazić SynchronousQueue jako sportowca ( nić ) biegnącego ze zniczem olimpijskim, który biegnie ze pochodnią (przedmiotem, który jest przekazywany dalej) i przekazuje ją innemu sportowcowi czekającemu po drugiej stronie. Jeśli zwrócisz uwagę na nazwę, zrozumiesz, że SynchronousQueue została tak nazwana nie bez powodu; przesyła dane synchronicznie do innego wątku ; czeka, aż ktoś pobierze dane, zamiast po prostu je umieścić i wyjść (operacja asynchroniczna). Jeśli znasz CSP i Adę, to wiesz, że zsynchronizowane kolejki przypominają spotkanie wątków. Dobrze nadają się do konstrukcji przesyłania sterowania, w których obiekt działający w jednym wątku musi zostać zsynchronizowany z obiektem w innym wątku, aby przekazać mu pewne informacje, zdarzenie lub zadanie. W poprzednich tutorialach dotyczących programowania wielowątkowego dowiedzieliśmy się, jak rozwiązać problem producent-konsument za pomocą metod oczekiwania i powiadamiania oraz BlockingQueue . Teraz dowiemy się, jak zastosować wzorzec producent-konsument za pomocą SynchronousQueue. Klasa ta dodatkowo wspiera uczciwe zachowanie przy porządkowaniu oczekiwań wątków producenta i konsumenta. Domyślnie taka kolejność nie jest gwarantowana. Jednakże kolejki utworzone z właściwościami fair gwarantują dostęp dla wątków w kolejce FIFO (Firs In First Out).
Producent/konsument używający SynchronousQueue w Javie.
Przykład SynchronousQueue w Javie - rozwiązanie problemu Producent Konsument - 1 Jak powiedziałem powyżej, nie ma nic lepszego niż problem producent-konsument w zrozumieniu komunikacji międzywątkowej w dowolnym języku programowania. W tym problemie jeden wątek pełni rolę producenta wytwarzającego zdarzenia i zadania, a drugi wątek pełni rolę ich konsumenta. Współdzielony bufor służy do przesyłania danych od producenta do konsumenta. Trudność w rozwiązaniu tego problemu pojawia się w skrajnych przypadkach, gdy na przykład producent jest zmuszony czekać, ponieważ... bufor jest pełny lub konsument jest zmuszony czekać, ponieważ bufor jest pusty. Można to było łatwo rozwiązać, ponieważ... Kolejka blokująca zapewniała nie tylko bufor do przechowywania danych, ale także kontrolę przepływu, blokując wątek wywołujący metodę put() (Producent) w przypadku zapełnienia bufora oraz blokując wątek wywołujący metodę take() (Consumer) w przypadku bufor był pusty. Teraz rozwiążemy ten sam problem, używając SynchronousQueue, specjalnego rodzaju kolekcji równoległych o zerowej pojemności. W poniższym przykładzie mamy dwa wątki o nazwie PRODUCER i CONSUMER (zawsze nadawaj wątkom nazwy, jest to bardzo dobry styl programowania wielowątkowego).Pierwszy wątek wpisuje wynik w grze, a drugi go konsumuje. Wynik w grze to nic innego jak obiekt typu String. Ale jeśli uruchomisz program z innym typem, nie zauważysz żadnej różnicy. Aby zrozumieć, jak działa SynchronousQueue i jak rozwiązać problem producent-konsument, musisz: albo uruchomić program do debugowania (debugowania) w środowisku Eclipse , albo po prostu uruchomić wątek producenta, komentując Consumer.start(); jeśli wątek konsumencki nie jest uruchomiony, wątek producenta zostanie zablokowany w kolejce.put(event); jeśli jest uruchomiony, nie będziesz mógł zobaczyć, jak producent [PRODUCER] publikuje wydarzenie :FOUR. Dzieje się tak, ponieważ specyficzne zachowanie SynchronousQueue, które zapewnia, że ​​wysyłanie danych przez wątek będzie blokowane do czasu, aż inny wątek pobierze dane i odwrotnie. Możesz przetestować resztę kodu, komentując producenta.start(); i rozpoczynając tylko wątek konsumencki. Jeśli dokładnie przestudiujesz dane wyjściowe programu, zauważysz, że kolejność wyników jest odwrotna. Wygląda na to, że wątek [CONSUMER] pobrał dane, zanim wątek [PRODUCER] je wygenerował. Dzieje się tak, ponieważ SynchronousQueue domyślnie nie gwarantuje kolejkowania. Ma jednak zasady uczciwości, które ustalają dostęp do wątków w kolejności FIFO. Możesz włączyć te reguły, przekazując wartość true do przeciążonego konstruktora SynchronousQueue w następujący sposób: 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 new SynchronousQueue(boolean fair).
O czym musisz pamiętać o SynchronousQueue w Javie.

Oto kilka ważnych właściwości tego specjalnego typu kolejki blokującej w Javie. Bardzo przydatne jest przesyłanie danych z jednego wątku do drugiego w sposób zsynchronizowany. Ta kolejka nie ma pojemności i jest blokowana do czasu zwolnienia jej przez inny wątek.

  1. SynchronousQueue blokuje i dopóki jeden wątek nie będzie gotowy do pobrania danych, inny będzie próbował je umieścić.
  2. Kolejka SynchronousQueue nie ma woluminu. Oznacza to, że nie zawiera danych.
  3. SynchronousQueue służy do implementowania strategii kolejkowania do przodu, w której wątek przekazuje kontrolę do wątku oczekującego lub tworzy nowy, jeśli jest to dozwolone, w przeciwnym razie kontrola nie jest przekazywana.
  4. Ta kolejka nie zezwala na dane o wartości null. Próba dodania elementu null spowoduje wygenerowanie wyjątku NullPointerException .
  5. Jeśli używasz innych metod z kolekcji (takich jak zawiera), SynchronousQueue zachowuje się jak pusta kolekcja.
  6. Nie możesz użyć metody podglądu SynchronousQueue, ponieważ element istnieje tylko wtedy, gdy próbujesz go usunąć; Ponadto nie będziesz mógł wstawiać elementów (przy użyciu dowolnej metody), dopóki inny wątek nie spróbuje ich usunąć.
  7. Nie będziesz mógł używać iteratora dla SynchronousQueue, ponieważ... nie ma żadnych elementów.
  8. SynchronousQueue można stworzyć na uczciwych zasadach, gdzie dostęp do wątków jest gwarantowany w kolejności FIFO.
Być może chodzi tu o SynchronousQueue w Javie. Przyjrzeliśmy się niektórym specjalnym cechom tej wielowątkowej kolekcji i dowiedzieliśmy się, jak rozwiązać klasyczny problem producent-konsument za pomocą SynchronousQueue w Javie. Swoją drogą nazywanie tego kolejką nie do końca jest poprawne, bo... nie zawiera elementów. Wywołanie put() nie zostanie zakończone, dopóki inny wątek nie wywoła take(). Bardziej poprawne jest myślenie o tym jako o miejscu spotkań wątków, w którym mają wspólny przedmiot. Innymi słowy, jest to narzędzie do zsynchronizowanego przekazywania obiektów w Javie, być może bezpieczniejsza alternatywa dla metody oczekiwania i powiadamiania .
Komentarze
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION