CodeGym /Java Blog /Willekeurig /Verschil tussen een Mutex, een monitor en een semafoor
John Squirrels
Niveau 41
San Francisco

Verschil tussen een Mutex, een monitor en een semafoor

Gepubliceerd in de groep Willekeurig
Hoi! Toen je multithreading op CodeGym bestudeerde, kwam je vaak de concepten "mutex" en "monitor" tegen. Kun je, zonder te gluren, zeggen hoe ze verschillen? :) Zo ja, goed gedaan! Zo niet (dit komt het meest voor), dan is dat geen verrassing. "Mutex" en "monitor" zijn eigenlijk gerelateerde concepten. Bovendien, als je lessen leest en video's bekijkt over multithreading op andere websites, kom je een ander soortgelijk concept tegen: "semafoor". Het heeft ook een zeer vergelijkbare functie als monitoren en mutexen. Daarom gaan we deze drie termen onderzoeken. We zullen een paar voorbeelden bekijken en tot een definitief begrip komen van hoe deze concepten van elkaar verschillen :)

Mutex

Een mutex (of slot) is een speciaal mechanisme voor het synchroniseren van threads. Eén is "gehecht" aan elk object in Java - dat weet je al :) Het maakt niet uit of je standaardklassen gebruikt of je eigen klassen maakt, bijvoorbeeld Cat en Dog : alle objecten van alle klassen hebben een mutex . De term "mutex" komt van "MUTual EXclusion", wat het doel perfect omschrijft. Zoals we in een van onze vorige lessen zeiden, maakt een mutex het mogelijk om ervoor te zorgen dat slechts één thread tegelijk toegang heeft tot het object. Een populair real-life voorbeeld van een mutex betreft toiletten. Wanneer een persoon een toiletwand betreedt, vergrendelt hij de deur van binnenuit. Het toilet is als een object dat toegankelijk is via meerdere draden. Het slot op de scheidingsdeur is als een mutex en de rij mensen buiten vertegenwoordigt draden. Het slot op de deur is de mutex van het toilet: het zorgt ervoor dat er maar één persoon naar binnen kan. Wat is het verschil tussen een mutex, een monitor en een semafoor?  - 2Met andere woorden, er kan slechts één thread tegelijk werken met gedeelde bronnen. Pogingen van andere threads (mensen) om toegang te krijgen tot bezette bronnen zullen mislukken. Een mutex heeft een aantal belangrijke kenmerken. Ten eerste zijn er slechts twee toestanden mogelijk: "ontgrendeld" en "vergrendeld". Dit helpt ons te begrijpen hoe het werkt: je kunt parallellen trekken met Booleaanse variabelen (waar/onwaar) of binaire getallen (0/1). , de staat kan niet rechtstreeks worden gecontroleerd. Java heeft geen mechanisme waarmee u expliciet een object kunt nemen, de mutex ervan kunt ophalen en de gewenste status kunt toewijzen. Met andere woorden, u kunt niet zoiets doen als:

Object myObject = new Object();
Mutex mutex = myObject.getMutex();
mutex.free();
Dit betekent dat u de mutex van een object niet kunt vrijgeven. Alleen de Java-machine heeft er directe toegang toe. Programmeurs werken met mutexen via de tools van de taal.

Monitor

Een monitor is een extra "bovenbouw" boven een mutex. In feite is een monitor een stuk code dat "onzichtbaar" is voor de programmeur. Toen we het eerder over mutexen hadden, gaven we een eenvoudig voorbeeld:

public class Main {

   private Object obj = new Object();

   public void doSomething() {

       // ...some logic, available for all threads

       synchronized (obj) {

           // Logic available to just one thread at a time
       }
   }
}
In het codeblok gemarkeerd met het gesynchroniseerde trefwoord wordt de mutex van ons obj- object verkregen. Geweldig, we kunnen het slot bemachtigen, maar hoe wordt de "bescherming" precies geboden? Als we het woord synchroon zien , wat verhindert dan dat de andere threads het blok binnenkomen? De bescherming komt van een monitor! De compiler zet het gesynchroniseerde sleutelwoord om in verschillende speciale stukjes code. Laten we nogmaals teruggaan naar ons voorbeeld met de methode doSomething() . We voegen er nog aan toe:

public class Main {

   private Object obj = new Object();

   public void doSomething() {

       // ...some logic, available for all threads

       // Logic available to just one thread at a time
       synchronized (obj) {

           /* Do important work that requires that the object
           be accessed by only one thread */
           obj.someImportantMethod();
       }
   }
}
Dit is wat er "onder de motorkap" gebeurt nadat de compiler deze code heeft geconverteerd:

public class Main {

   private Object obj = new Object();

   public void doSomething() throws InterruptedException {

       // ...some logic, available for all threads

       // Logic available to just one thread at a time:
     
       /* as long as the object's mutex is busy,
       all the other threads (except the one that acquired it) are put to sleep */
       while (obj.getMutex().isBusy()) {
           Thread.sleep(1);
       }

       // Mark the object's mutex as busy
       obj.getMutex().isBusy() = true;

       /* Do important work that requires that the object
       be accessed by only one thread */
       obj.someImportantMethod();

       // Free the object's mutex
       obj.getMutex().isBusy() = false;
   }
}
Dit is natuurlijk geen echt voorbeeld. Hier hebben we Java-achtige code gebruikt om weer te geven wat er in de Java-machine gebeurt. Dat gezegd hebbende, geeft deze pseudocode een uitstekend inzicht in wat er feitelijk gebeurt met het object en de threads in het gesynchroniseerde blok en hoe de compiler dit sleutelwoord omzet in verschillende verklaringen die "onzichtbaar" zijn voor de programmeur. Kortom, Java gebruikt het gesynchroniseerde trefwoord om een ​​monitor weer te geven . Alle code die verschijnt in plaats van het gesynchroniseerde trefwoord in het laatste voorbeeld is de monitor.

Semafoor

Een ander woord dat u zult tegenkomen in uw persoonlijke studie van multithreading is "semafoor". Laten we eens kijken wat dit is en hoe het verschilt van een monitor en een mutex. Een semafoor is een hulpmiddel om de toegang tot een bepaalde bron te synchroniseren. Het onderscheidende kenmerk is dat het een teller gebruikt om het synchronisatiemechanisme te creëren. De teller vertelt ons hoeveel threads tegelijkertijd toegang hebben tot de gedeelde bron. Wat is het verschil tussen een mutex, een monitor en een semafoor?  - 3Semaphores in Java worden vertegenwoordigd door de Semaphore- klasse. Bij het maken van semafoorobjecten kunnen we de volgende constructors gebruiken:

Semaphore(int permits)
Semaphore(int permits, boolean fair)
We geven het volgende door aan de constructor:
    int permits — de begin- en maximumwaarde van de teller. Met andere woorden, deze parameter bepaalt hoeveel threads tegelijkertijd toegang hebben tot de gedeelde bron;
  • boolean fair — bepaalt de volgorde waarin threads toegang krijgen. Als fair waar is, wordt toegang verleend aan wachtende threads in de volgorde waarin ze erom hebben gevraagd. Als het onwaar is, wordt de volgorde bepaald door de threadplanner.
Een klassiek voorbeeld van het gebruik van semafoor is het probleem van de eetfilosoof. Wat is het verschil tussen een mutex, een monitor en een semafoor?  - 4Om het begrip te vergemakkelijken, vereenvoudigen we het een beetje. Stel je voor dat we 5 filosofen hebben die moeten lunchen. Daarnaast hebben we één tafel waar niet meer dan twee personen tegelijkertijd aan kunnen zitten. Onze taak is om alle filosofen te voeden. Geen van hen zou honger moeten lijden, en geen van hen zou elkaar moeten "blokkeren" wanneer ze aan tafel proberen te gaan zitten (we moeten een impasse vermijden). Dit is hoe onze filosofenklas eruit zal zien:

class Philosopher extends Thread {

   private Semaphore sem;

   // Did the philosopher eat?
   private boolean full = false;

   private String name;

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

   public void run()
   {
       try
       {
           // If the philosopher has not eaten
           if (!full) {
               // Ask the semaphore for permission to run
               sem.acquire();
               System.out.println(name + " takes a seat at the table");

               // The philosopher eats
               sleep(300);
               full = true;

               System.out.println(name + " has eaten! He leaves the table");
               sem.release();

               // The philosopher leaves, making room for others
               sleep(300);
           }
       }
       catch(InterruptedException e) {
           System.out.println("Something went wrong!");
       }
   }
}
En hier is de code om ons programma uit te voeren:

public class Main {

   public static void main(String[] args) {

       Semaphore sem = new Semaphore(2);
       new Philosopher(sem, "Socrates").start();
       new Philosopher(sem,"Plato").start();
       new Philosopher(sem,"Aristotle").start();
       new Philosopher(sem, "Thales").start();
       new Philosopher(sem, "Pythagoras").start();
   }
}
We hebben een semafoor gemaakt waarvan de teller op 2 staat om te voldoen aan de voorwaarde: er kunnen maar twee filosofen tegelijk eten. Dat wil zeggen, er kunnen slechts twee threads tegelijkertijd worden uitgevoerd, omdat onze Philosopher- klasse Thread ! De methoden acquire() en release() van de klasse Semaphore bepalen de toegangsteller. De methode acquire() vraagt ​​de semafoor om toegang tot de bron. Als de teller >0 is, wordt toegang verleend en wordt de teller met 1 verlaagd. De release()methode "geeft" de eerder verleende toegang vrij en retourneert deze naar de teller (verhoogt de toegangsteller van de semafoor met 1). Wat krijgen we als we het programma uitvoeren? Is het probleem opgelost? Zullen onze filosofen niet vechten terwijl ze op hun beurt wachten? :) Dit is de console-uitvoer die we hebben:

Socrates takes a seat at the table 
Plato takes a seat at the table 
Socrates has eaten! He leaves the table 
Plato has eaten! He leaves the table 
Aristotle takes a seat at the table 
Pythagoras takes a seat at the table 
Aristotle has eaten! He leaves the table 
Pythagoras has eaten! He leaves the table 
Thales takes a seat at the table 
Thales has eaten! He leaves the table 
We hebben het gedaan! En hoewel Thales alleen moest dineren, denk ik niet dat we hem hebben beledigd :) Je hebt misschien enkele overeenkomsten opgemerkt tussen een mutex en een semafoor. Ze hebben inderdaad dezelfde missie: de toegang tot een bepaalde bron synchroniseren. Wat is het verschil tussen een mutex, een monitor en een semafoor?  - 5Het enige verschil is dat de mutex van een object slechts door één thread tegelijk kan worden verkregen, terwijl in het geval van een semafoor, die een threadteller gebruikt, meerdere threads tegelijkertijd toegang hebben tot de bron. Dit is geen toeval :) Een mutex is eigenlijk een semafoormet een telling van 1. Met andere woorden, het is een semafoor die plaats biedt aan een enkele thread. Het staat ook bekend als een "binaire semafoor" omdat de teller slechts 2 waarden kan hebben: 1 ("ontgrendeld") en 0 ("vergrendeld"). Dat is het! Zoals je kunt zien, is het toch niet zo verwarrend :) Als je multithreading in meer detail op internet wilt bestuderen, zal het iets gemakkelijker voor je zijn om door deze concepten te navigeren. Tot ziens in de volgende lessen!
Opmerkingen
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION