CodeGym /Java blog /Tilfældig /Forskellen mellem en Mutex, en skærm og en semafor
John Squirrels
Niveau
San Francisco

Forskellen mellem en Mutex, en skærm og en semafor

Udgivet i gruppen
Hej! Når du studerede multithreading på CodeGym, stødte du ofte på begreberne "mutex" og "monitor". Uden at kigge, kan du sige, hvordan de adskiller sig? :) Hvis ja, godt gået! Hvis ikke (dette er mest almindeligt), er det ingen overraskelse. "Mutex" og "monitor" er faktisk relaterede begreber. Derudover, når du læser lektioner og ser videoer om multithreading på andre websteder, vil du støde på et andet lignende koncept: "semafor". Den har også en meget lignende funktion til monitorer og mutexes. Det er derfor, vi vil undersøge disse tre udtryk. Vi vil se på et par eksempler og komme til en endelig forståelse af, hvordan disse begreber adskiller sig fra hinanden :)

Mutex

En mutex (eller lås) er en speciel mekanisme til synkronisering af tråde. En er "knyttet" til hvert objekt i Java — det ved du allerede :) Det er lige meget om du bruger standardklasser eller opretter dine egne klasser, f.eks. Cat and Dog : alle objekter i alle klasser har en mutex . Udtrykket "mutex" kommer fra "MUTual EXclusion", som perfekt beskriver dens formål. Som vi sagde i en af ​​vores tidligere lektioner, gør en mutex det muligt at sikre, at kun én tråd ad gangen har adgang til objektet. Et populært virkeligt eksempel på en mutex involverer toiletter. Når en person kommer ind i en toiletskillevæg, låser han døren indefra. Toilettet er som en genstand, der kan tilgås af flere tråde. Låsen på skillevægsdøren er som en mutex, og linjen af ​​mennesker udenfor repræsenterer tråde. Låsen på døren er toilettets mutex: Den sikrer, at kun én person kan komme ind. Hvad er forskellen mellem en mutex, en skærm og en semafor?  - 2Med andre ord kan kun én tråd ad gangen arbejde med delte ressourcer. Forsøg fra andre tråde (personer) på at få adgang til besatte ressourcer vil mislykkes. En mutex har flere vigtige funktioner. For det første er kun to tilstande mulige: "ulåst" og "låst". Dette hjælper os med at forstå, hvordan det virker: du kan drage paralleller med boolske variable (sand/falsk) eller binære tal (0/1). , kan staten ikke kontrolleres direkte. Java har ingen mekanisme, der vil lade dig eksplicit tage et objekt, få dets mutex og tildele den ønskede status. Du kan med andre ord ikke gøre noget som:

Object myObject = new Object();
Mutex mutex = myObject.getMutex();
mutex.free();
Det betyder, at du ikke kan frigive et objekts mutex. Kun Java-maskinen har direkte adgang til den. Programmører arbejder med mutexes gennem sprogets værktøjer.

Overvåge

En monitor er en ekstra "overbygning" over en mutex. Faktisk er en skærm et stykke kode, der er "usynlig" for programmøren. Da vi talte om mutexes tidligere, gav vi et simpelt eksempel:

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 kodeblokken, der er markeret med det synkroniserede nøgleord, optages mutexen for vores obj- objekt. Godt, vi kan erhverve låsen, men hvordan er "beskyttelsen" præcis ydet? Når vi ser ordet synkroniseret , hvad forhindrer de andre tråde i at komme ind i blokken? Beskyttelsen kommer fra en skærm! Compileren konverterer det synkroniserede nøgleord til flere specielle kodestykker. Endnu en gang, lad os vende tilbage til vores eksempel med doSomething() -metoden. Vi tilføjer til det:

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();
       }
   }
}
Her er, hvad der sker "under motorhjelmen", efter at compileren konverterer denne kode:

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;
   }
}
Selvfølgelig er dette ikke et rigtigt eksempel. Her brugte vi Java-lignende kode til at skildre, hvad der sker inde i Java-maskinen. Når det er sagt, giver denne pseudo-kode en fremragende forståelse af, hvad der faktisk sker med objektet og trådene inde i den synkroniserede blok, og hvordan compileren konverterer dette nøgleord til flere udsagn, der er "usynlige" for programmøren. Grundlæggende bruger Java det synkroniserede nøgleord til at repræsentere en skærm . Al den kode, der vises i stedet for det synkroniserede nøgleord i det sidste eksempel, er monitoren.

Semafor

Et andet ord, du vil støde på i din personlige undersøgelse af multithreading, er "semafor". Lad os finde ud af, hvad dette er, og hvordan det adskiller sig fra en skærm og en mutex. En semafor er et værktøj til at synkronisere adgang til en ressource. Dens karakteristiske træk er, at den bruger en tæller til at skabe synkroniseringsmekanismen. Tælleren fortæller os, hvor mange tråde der kan få adgang til den delte ressource samtidigt. Hvad er forskellen mellem en mutex, en skærm og en semafor?  - 3Semaforer i Java er repræsenteret af Semaphore -klassen. Når vi opretter semaforobjekter, kan vi bruge følgende konstruktører:

Semaphore(int permits)
Semaphore(int permits, boolean fair)
Vi videregiver følgende til konstruktøren:
    int permits — tællerens indledende og maksimale værdi. Med andre ord bestemmer denne parameter, hvor mange tråde der kan få adgang til den delte ressource samtidigt;
  • boolean fair — fastlægger rækkefølgen, hvori tråde får adgang. Hvis fair er sandt, gives der adgang til ventende tråde i den rækkefølge, de anmodede om det. Hvis det er falsk, bestemmes rækkefølgen af ​​trådplanlæggeren.
Et klassisk eksempel på semaforbrug er spisefilosofproblemet. Hvad er forskellen mellem en mutex, en skærm og en semafor?  - 4For at lette forståelsen vil vi forenkle det en smule. Forestil dig, at vi har 5 filosoffer, der skal spise frokost. Derudover har vi ét bord, der samtidig ikke kan rumme mere end to personer. Vores opgave er at brødføde alle filosofferne. Ingen af ​​dem skal sulte, og ingen af ​​dem skal "blokere" hinanden, når de forsøger at sætte sig til bords (vi skal undgå dødvande). Sådan kommer vores filosofklasse til at se ud:

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!");
       }
   }
}
Og her er koden til at køre vores 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 lavede en semafor, hvis tæller er sat til 2 for at opfylde betingelsen: kun to filosoffer kan spise på samme tid. Det vil sige, at kun to tråde kan køre på samme tid, fordi vores Philosopher- klasse arver Thread ! Acquisit () og release() metoderne i Semaphore -klassen styrer dens adgangstæller. Acquisit()-metoden beder semaforen om adgang til ressourcen. Hvis tælleren er >0, gives der adgang, og tælleren reduceres med 1. Frigivelsen ()metoden "frigiver" den tidligere tildelte adgang og returnerer den til tælleren (forøger semaforens adgangstæller med 1). Hvad får vi, når vi kører programmet? Er problemet løst? Vil vores filosoffer ikke kæmpe, mens de venter på deres tur? :) Her er konsoludgangen, vi fik:

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! Og selvom Thales skulle spise alene, tror jeg ikke, vi har fornærmet ham :) Du har måske bemærket nogle ligheder mellem en mutex og en semafor. Faktisk har de den samme mission: at synkronisere adgang til en eller anden ressource. Hvad er forskellen mellem en mutex, en skærm og en semafor?  - 5Den eneste forskel er, at et objekts mutex kun kan erhverves af én tråd ad gangen, mens i tilfælde af en semafor, som bruger en trådtæller, kan flere tråde få adgang til ressourcen samtidigt. Dette er ikke kun en tilfældighed :) En mutex er faktisk en semaformed et tal på 1. Det er med andre ord en semafor, der kan rumme en enkelt tråd. Det er også kendt som en "binær semafor", fordi dens tæller kun kan have 2 værdier - 1 ("ulåst") og 0 ("låst"). Det er det! Som du kan se, er det alligevel ikke så forvirrende :) Hvis du nu vil studere multithreading mere detaljeret på internettet, vil det være lidt nemmere for dig at navigere i disse begreber. Vi ses i de næste lektioner!
Kommentarer
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION