JavaRush /Blog Java /Random-PL /Jaka jest różnica między muteksem, monitorem i semaforem

Jaka jest różnica między muteksem, monitorem i semaforem

Opublikowano w grupie Random-PL
Cześć! Studiując wielowątkowość w JavaRush, często spotykałeś się z pojęciami „mutex” i „monitor”. Czy możesz teraz bez podglądania odpowiedzieć czym się różnią? :) Jaka jest różnica między muteksem, monitorem i semaforem - 1Gdybyś mógł, dobra robota! Jeśli nie (a najczęściej tak się dzieje) – nic dziwnego. Pojęcia „mutex” i „monitor” są rzeczywiście powiązane. Co więcej, czytając wykłady i oglądając filmy na temat wielowątkowości na zasobach zewnętrznych w Internecie, natkniesz się na inną podobną koncepcję - „semafor”. Jego funkcjonalność jest również w dużej mierze podobna do monitora i mutexu. Dlatego zrozumiejmy te trzy pojęcia, spójrzmy na kilka przykładów i wreszcie uporządkujmy w głowach zrozumienie, czym się od siebie różnią :)

Muteks

Mutex to specjalny obiekt służący do synchronizacji wątków. Jest „dołączony” do każdego obiektu w Javie - już to wiesz :) Nie ma znaczenia, czy używasz klas standardowych, czy tworzysz własne, powiedzmy, Cati Dog: wszystkie obiekty wszystkich klas mają muteks . Nazwa „mutex” pochodzi od angielskiego „MUTual EXclusion” – „wzajemne wykluczenie” i to doskonale oddaje jego przeznaczenie. Jak powiedzieliśmy w jednym z poprzednich wykładów, zadaniem mutexu jest zapewnienie takiego mechanizmu, aby w określonym czasie dostęp do obiektu miał tylko jeden wątek . Popularną analogią muteksu w prawdziwym życiu jest „przykład toalety”. Kiedy ktoś wchodzi do toalety, zamyka drzwi od środka. Toaleta pełni rolę obiektu, do którego można uzyskać dostęp za pomocą wielu wątków. Zamek w drzwiach toalety pełni rolę muteksu, a kolejka ludzi na zewnątrz pełni rolę nitek. Zamek w drzwiach to muteks toaletowy: zapewnia, że ​​w środku może przebywać tylko jedna osoba w danym momencie. Jaka jest różnica między muteksem, monitorem i semaforem - 2Innymi słowy, tylko jeden wątek na raz może pracować na współdzielonych zasobach. Próby uzyskania dostępu do zajętych zasobów przez inne wątki (ludzie) nie powiodą się. Mutex ma kilka ważnych cech. Po pierwsze , możliwe są tylko dwa stany – „wolny” i „zajęty”. Ułatwia to zrozumienie, jak to działa: podobieństwa można narysować za pomocą zmiennych boolowskich prawda/fałsz lub systemu liczb binarnych 1/0. Po drugie , stanami nie można sterować bezpośrednio. W Javie nie ma mechanizmów, które pozwalałyby na jawne pobranie obiektu, pobranie jego muteksu i przypisanie mu żądanego statusu. Innymi słowy, nie możesz zrobić czegoś takiego:
Object myObject = new Object();
Mutex mutex = myObject.getMutex();
mutex.free();
Zatem muteks obiektu nie może zostać zwolniony. Tylko maszyna Java ma do niego bezpośredni dostęp. Programiści pracują z muteksami za pomocą narzędzi językowych.

Monitor

Monitor to dodatkowy „dodatek” do mutexu. Tak naprawdę monitor jest fragmentem kodu „niewidocznym” dla programisty . Mówiąc o muteksie wcześniej, podaliśmy prosty przykład:
public class Main {

   private Object obj = new Object();

   public void doSomething() {

       //... pewna logika dostępna dla wszystkich wątków

       synchronized (obj) {

           //logika, która jest dostępna tylko dla jednego wątku naraz
       }
   }
}
W bloku kodu oznaczonym słowem synchronizedprzechwytywany jest muteks naszego obiektu obj. OK, przechwytywanie następuje, ale jak dokładnie realizowany jest „mechanizm obronny”? synchronizedDlaczego inne wątki nie mogą wejść do bloku, gdy zobaczą słowo ? To monitor tworzy mechanizm ochronny! Kompilator konwertuje słowo synchronizedna kilka specjalnych fragmentów kodu. Jeszcze raz wróćmy do naszego przykładu z metodą doSomething()i dodajmy do niego:
public class Main {

   private Object obj = new Object();

   public void doSomething() {

       //... pewna logika dostępna dla wszystkich wątków

       //logika, która jest dostępna tylko dla jednego wątku naraz
       synchronized (obj) {

           /*выполнить важную работу, при которой доступ к obiektу
           должен быть только у одного потока*/
           obj.someImportantMethod();
       }
   }
}
Oto, co stanie się „pod maską” naszego programu po przekonwertowaniu tego kodu przez kompilator:
public class Main {

   private Object obj = new Object();

   public void doSomething() throws InterruptedException {

       //... pewna logika dostępna dla wszystkich wątków

       //логика, которая одновременно доступна только для одного потока:

       /*до тех пор, пока мьютекс obiektа занят -
       любой другой поток (кроме того, который его захватил), спит*/
       while (obj.getMutex().isBusy()) {
           Thread.sleep(1);
       }

       //пометить мьютекс obiektа Jak занятый
       obj.getMutex().isBusy() = true;

       /*выполнить важную работу, при которой доступ к obiektу
       должен быть только у одного потока*/
       obj.someImportantMethod();

       //освободить мьютекс obiektа
       obj.getMutex().isBusy() = false;
   }
}
Przykład oczywiście nie jest prawdziwy. Tutaj, używając kodu przypominającego Javę, staraliśmy się odzwierciedlić to, co dzieje się w tym momencie wewnątrz maszyny Java. Jednak ten pseudokod pozwala doskonale zrozumieć, co faktycznie dzieje się z obiektem i wątkami wewnątrz bloku synchronizedoraz w jaki sposób kompilator konwertuje to słowo na kilka poleceń, które są „niewidoczne” dla programisty. Zasadniczo monitor w Javie wyraża się za pomocą słowasynchronized . Cały kod, który pojawił się zamiast słowa synchronizedw ostatnim przykładzie, to monitor.

Semafor

Innym słowem, które można spotkać podczas samodzielnej nauki wielowątkowości, jest „semafor”. Zastanówmy się, co to jest i czym różni się od monitora i muteksu. Semafor to sposób na synchronizację dostępu do zasobu. Jego osobliwością jest to, że podczas tworzenia mechanizmu synchronizacji wykorzystuje licznik. Licznik informuje nas, ile wątków może jednocześnie uzyskać dostęp do współdzielonego zasobu. Jaka jest różnica między muteksem, monitorem i semaforem - 3Semafory w Javie są reprezentowane przez klasę Semaphore. Tworząc obiekty semaforowe możemy skorzystać z następujących konstruktorów:
Semaphore(int permits)
Semaphore(int permits, boolean fair)
Przechodzimy do konstruktora:
  • int permits— początkowa i maksymalna wartość licznika. Oznacza to, ile wątków może jednocześnie uzyskać dostęp do współdzielonego zasobu;

  • boolean fair- aby ustalić kolejność, w jakiej wątki będą otrzymywały dostęp. Jeśli fair= true , dostęp jest przyznawany oczekującym wątkom w kolejności, w jakiej o to poprosiły. Jeśli ma wartość false , kolejność zostanie ustalona przez planistę wątków.

Klasycznym przykładem zastosowania semaforów jest problem lunchowych filozofów .
Jaka jest różnica między muteksem, monitorem i semaforem - 4
Uprościmy nieco jego warunki dla lepszego zrozumienia. Wyobraź sobie, że mamy 5 filozofów, którzy potrzebują lunchu. Jednocześnie mamy jeden stół i nie mogą przy nim przebywać jednocześnie więcej niż dwie osoby. Naszym zadaniem jest nakarmić wszystkich filozofów. Żadne z nich nie powinno głodować, ani też nie powinno się „blokować” przy próbie siadania do stołu (trzeba unikać impasu). Tak będą wyglądać nasze zajęcia z filozofami:
class Philosopher extends Thread {

   private Semaphore sem;

   // поел ли философ
   private boolean full = false;

   private String name;

   Philosopher(Semaphore sem, String name) {
       this.sem=sem;
       this.name=name;
   }

   public void run()
   {
       try
       {
           // если философ еще не ел
           if (!full) {
               //Запрашиваем у семафора разрешение на выполнение
               sem.acquire();
               System.out.println (name + " садится за стол");

               // философ ест
               sleep(300);
               full = true;

               System.out.println (name + " поел! Он выходит из-за стола");
               sem.release();

               // философ ушел, освободив место другим
               sleep(300);
           }
       }
       catch(InterruptedException e) {
           System.out.println ("Co-то пошло не так!");
       }
   }
}
A oto kod uruchamiający nasz program:
public class Main {

   public static void main(String[] args) {

       Semaphore sem = new Semaphore(2);
       new Philosopher(sem,"Сократ").start();
       new Philosopher(sem,"Платон").start();
       new Philosopher(sem,"Аристотель").start();
       new Philosopher(sem,"Фалес").start();
       new Philosopher(sem,"Пифагор").start();
   }
}
Stworzyliśmy semafor z licznikiem 2, aby spełnić warunek, że tylko dwóch filozofów może jeść jednocześnie. Oznacza to, że jednocześnie mogą działać tylko dwa wątki, ponieważ nasza klasa Philosopherjest dziedziczona z Thread! Klasa acquire()i metody kontrolują licznik uprawnień. Metoda żąda pozwolenia na dostęp do zasobu z semafora. Jeżeli licznik > 0, zezwolenie zostaje udzielone, a licznik jest zmniejszany o 1. Metoda „zwalnia” wcześniej przyznane zezwolenie i zwraca je do licznika (zwiększając licznik uprawnień semafora o 1). Co otrzymamy uruchamiając program? Czy problem został rozwiązany, czy nasi filozofowie będą walczyć, czekając na swoją kolej? :) Oto wynik konsoli, który otrzymaliśmy: Sokrates siada przy stole Platon siada przy stole, który Sokrates zjadł! Odchodzi od stołu, Platon zjadł! Odchodzi od stołu Arystoteles siada przy stole Pitagoras siada przy stole, który Arystoteles zjadł! Odchodzi od stołu, który zjadł Pitagoras! Odchodzi od stołu, Thales siada przy stole, który Thales zjadł! Odchodzi od stołu. Udało się! I chociaż Tales musiał zjeść obiad sam, myślę, że nie jest na nas zły :) Być może zauważyliście pewne podobieństwa pomiędzy muteksem a semaforem. Ogólnie rzecz biorąc, mają ten sam cel: synchronizację dostępu do niektórych zasobów. Jedyna różnica polega na tym, że mutex obiektu może zostać pobrany tylko przez jeden wątek na raz, natomiast w przypadku semafora używany jest licznik wątków i kilka z nich może uzyskać dostęp do zasobu jednocześnie. I nie jest to tylko przypadkowe podobieństwo :) Tak naprawdę mutex jest semaforem jednomiejscowym . Oznacza to, że jest to semafor, którego licznik jest początkowo ustawiony na 1. Nazywa się go również „semaforem binarnym”, ponieważ jego licznik może mieć tylko 2 wartości - 1 („wolny”) i 0 („zajęty”). To wszystko! Jak widać, wszystko okazało się nie takie zagmatwane :) Teraz, jeśli chcesz bardziej szczegółowo przestudiować temat wielowątkowości w Internecie, będzie ci trochę łatwiej poruszać się po pojęciach. Do zobaczenia na kolejnych lekcjach! release()Semaphoreacquire()release()Jaka jest różnica między muteksem, monitorem i semaforem - 5
Komentarze
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION