CodeGym /Java blogg /Slumpmässig /Skillnaden mellan en Mutex, en monitor och en semafor
John Squirrels
Nivå
San Francisco

Skillnaden mellan en Mutex, en monitor och en semafor

Publicerad i gruppen
Hej! När du studerade multithreading på CodeGym, stötte du ofta på begreppen "mutex" och "monitor". Utan att kika, kan du säga hur de skiljer sig åt? :) Om ja, bra jobbat! Om inte (detta är vanligast) är det ingen överraskning. "Mutex" och "monitor" är faktiskt relaterade begrepp. Dessutom, när du läser lektioner och tittar på videor om multithreading på andra webbplatser, kommer du att stöta på ett annat liknande koncept: "semafor". Den har också en mycket liknande funktion som monitorer och mutexes. Det är därför vi kommer att undersöka dessa tre termer. Vi ska titta på några exempel och komma till en definitiv förståelse av hur dessa begrepp skiljer sig från varandra :)

Mutex

En mutex (eller lås) är en speciell mekanism för att synkronisera trådar. En är "kopplad" till varje objekt i Java — det vet du redan :) Det spelar ingen roll om du använder standardklasser eller skapar dina egna klasser, t.ex. Cat and Dog : alla objekt i alla klasser har en mutex . Termen "mutex" kommer från "MUTual EXclusion", som perfekt beskriver dess syfte. Som vi sa i en av våra tidigare lektioner gör en mutex det möjligt att säkerställa att endast en tråd åt gången har tillgång till objektet. Ett populärt verkligt exempel på en mutex involverar toaletter. När en person går in i en toalettvägg låser han dörren från insidan. Toaletten är som ett föremål som kan nås av flera trådar. Låset på skiljedörren är som en mutex, och raden av människor utanför representerar trådar. Låset på dörren är toalettens mutex: det ser till att endast en person kan komma in. Vad är skillnaden mellan en mutex, en monitor och en semafor?  - 2Med andra ord kan bara en tråd åt gången arbeta med delade resurser. Försök från andra trådar (personer) att få tillgång till ockuperade resurser kommer att misslyckas. En mutex har flera viktiga egenskaper. För det första är endast två tillstånd möjliga: "olåst" och "låst". Detta hjälper oss att förstå hur det fungerar: du kan dra paralleller med booleska variabler (sant/falskt) eller binära tal (0/1). , staten kan inte kontrolleras direkt. Java har ingen mekanism som låter dig explicit ta ett objekt, hämta dess mutex och tilldela önskad status. Du kan med andra ord inte göra något som:

Object myObject = new Object();
Mutex mutex = myObject.getMutex();
mutex.free();
Det betyder att du inte kan släppa ett objekts mutex. Endast Java-maskinen har direkt tillgång till den. Programmerare arbetar med mutexes genom språkets verktyg.

Övervaka

En monitor är en extra "överbyggnad" över en mutex. Faktum är att en bildskärm är en bit kod som är "osynlig" för programmeraren. När vi pratade om mutex tidigare gav vi ett enkelt exempel:

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
       }
   }
}
I kodblocket märkt med det synkroniserade nyckelordet förvärvas mutex för vårt obj -objekt. Bra, vi kan skaffa låset, men exakt hur tillhandahålls "skyddet"? När vi ser ordet synchronized , vad hindrar de andra trådarna från att komma in i blocket? Skyddet kommer från en bildskärm! Kompilatorn konverterar det synkroniserade nyckelordet till flera speciella kodbitar. Återigen, låt oss återgå till vårt exempel med metoden doSomething() . Vi lägger till:

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();
       }
   }
}
Här är vad som händer "under huven" efter att kompilatorn konverterar den här koden:

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;
   }
}
Naturligtvis är detta inte ett riktigt exempel. Här använde vi Java-liknande kod för att skildra vad som händer inuti Java-maskinen. Som sagt, den här pseudokoden ger en utmärkt förståelse för vad som faktiskt händer med objektet och trådarna inuti det synkroniserade blocket och hur kompilatorn konverterar detta nyckelord till flera påståenden som är "osynliga" för programmeraren. I grund och botten använder Java det synkroniserade nyckelordet för att representera en bildskärm . All kod som visas istället för det synkroniserade nyckelordet i det sista exemplet är monitorn.

Semafor

Ett annat ord som du kommer att stöta på i din personliga studie av multithreading är "semafor". Låt oss ta reda på vad detta är och hur det skiljer sig från en monitor och en mutex. En semafor är ett verktyg för att synkronisera åtkomst till någon resurs. Dess särdrag är att den använder en räknare för att skapa synkroniseringsmekanismen. Räknaren talar om för oss hur många trådar som samtidigt kan komma åt den delade resursen. Vad är skillnaden mellan en mutex, en monitor och en semafor?  - 3Semaforer i Java representeras av klassen Semaphore . När vi skapar semaforobjekt kan vi använda följande konstruktorer:

Semaphore(int permits)
Semaphore(int permits, boolean fair)
Vi skickar följande till konstruktören:
    int tillåter — räknarens initiala och maximala värde. Med andra ord bestämmer den här parametern hur många trådar som samtidigt kan komma åt den delade resursen;
  • boolean fair — fastställer i vilken ordning trådar kommer att få åtkomst. Om rättvist är sant, beviljas åtkomst till väntande trådar i den ordning som de begärde det. Om det är falskt bestäms ordningen av trådschemaläggaren.
Ett klassiskt exempel på semaforanvändning är middagsfilosofproblemet. Vad är skillnaden mellan en mutex, en monitor och en semafor?  - 4För att underlätta förståelsen kommer vi att förenkla det lite. Föreställ dig att vi har 5 filosofer som behöver äta lunch. Dessutom har vi ett bord som samtidigt rymmer högst två personer. Vår uppgift är att mata alla filosofer. Ingen av dem ska gå hungrig, och ingen av dem ska "blockera" varandra när de försöker sätta sig vid bordet (vi måste undvika dödläge). Så här kommer vår filosofklass att se ut:

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!");
       }
   }
}
Och här är koden för att köra vårt program:

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();
   }
}
Vi skapade en semafor vars räknare är inställd på 2 för att uppfylla villkoret: bara två filosofer kan äta samtidigt. Det vill säga, bara två trådar kan köras samtidigt, eftersom vår Philosopher -klass ärver Thread ! Acquisit ()- och release()- metoderna i klassen Semaphore styr dess åtkomsträknare. Acquisit()-metoden frågar semaforen om åtkomst till resursen. Om räknaren är >0, beviljas åtkomst och räknaren reduceras med 1. Release( )metoden "släpper" den tidigare beviljade åtkomsten och returnerar den till räknaren (ökar semaforens åtkomsträknare med 1). Vad får vi när vi kör programmet? Är problemet löst? Kommer inte våra filosofer att slåss medan de väntar på sin tur? :) Här är konsolutgången vi fick:

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 
Vi gjorde det! Och även om Thales var tvungen att äta ensam, tror jag inte att vi har förolämpat honom :) Du kanske har märkt några likheter mellan en mutex och en semafor. De har faktiskt samma uppdrag: att synkronisera åtkomst till någon resurs. Vad är skillnaden mellan en mutex, en monitor och en semafor?  - 5Den enda skillnaden är att ett objekts mutex kan förvärvas av endast en tråd åt gången, medan i fallet med en semafor, som använder en trådräknare, kan flera trådar komma åt resursen samtidigt. Detta är inte bara en slump :) En mutex är faktiskt en semaformed ett antal 1. Med andra ord är det en semafor som kan rymma en enda tråd. Den är också känd som en "binär semafor" eftersom dess räknare bara kan ha 2 värden - 1 ("olåst") och 0 ("låst"). Det är allt! Som du kan se är det inte så förvirrande trots allt :) Om du nu vill studera multithreading mer i detalj på Internet blir det lite lättare för dig att navigera i dessa begrepp. Vi ses på nästa lektion!
Kommentarer
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION