CodeGym /Java Blog /Random /Pagkakaiba sa pagitan ng Mutex, Monitor, at Semaphore
John Squirrels
Antas
San Francisco

Pagkakaiba sa pagitan ng Mutex, Monitor, at Semaphore

Nai-publish sa grupo
Hi! Noong nag-aral ka ng multithreading sa CodeGym, madalas kang makatagpo ng mga konsepto ng "mutex" at "monitor". Nang hindi sumilip, masasabi mo ba kung paano sila naiiba? :) Kung oo, magaling! Kung hindi (ito ang pinakakaraniwan), hindi iyon nakakagulat. Ang "Mutex" at "monitor" ay talagang magkaugnay na mga konsepto. Bukod pa rito, kapag nagbasa ka ng mga aralin at nanood ng mga video tungkol sa multithreading sa ibang mga website, makakatagpo ka ng isa pang katulad na konsepto: "semaphore". Mayroon din itong halos kaparehong function sa mga monitor at mutex. Kaya naman iimbestigahan natin ang tatlong terminong ito. Titingnan natin ang ilang mga halimbawa at darating sa isang tiyak na pag-unawa kung paano naiiba ang mga konseptong ito sa isa't isa :)

Mutex

Ang mutex (o lock) ay isang espesyal na mekanismo para sa pag-synchronize ng mga thread. Ang isa ay "naka-attach" sa bawat bagay sa Java — alam mo na iyon :) Hindi mahalaga kung gumamit ka ng mga karaniwang klase o lumikha ng sarili mong mga klase, hal. Cat at Aso : lahat ng bagay sa lahat ng klase ay may mutex . Ang terminong "mutex" ay nagmula sa "MUTual Exclusion", na perpektong naglalarawan sa layunin nito. Tulad ng sinabi namin sa isa sa aming mga nakaraang aralin, ang isang mutex ay ginagawang posible upang matiyak na isang thread lamang sa isang pagkakataon ang may access sa bagay. Ang isang sikat na halimbawa sa totoong buhay ng isang mutex ay nagsasangkot ng mga palikuran. Kapag ang isang tao ay pumasok sa isang toilet partition, ini-lock niya ang pinto mula sa loob. Ang banyo ay parang isang bagay na maaaring ma-access ng maraming mga thread. Ang lock sa pinto ng partition ay parang mutex, at ang linya ng mga tao sa labas ay kumakatawan sa mga thread. Ang lock sa pinto ay ang mutex ng banyo: tinitiyak nito na isang tao lang ang makapasok sa loob. Ano ang pagkakaiba sa pagitan ng isang mutex, isang monitor, at isang semaphore?  - 2Sa madaling salita, isang thread lang sa isang pagkakataon ang maaaring gumana sa mga nakabahaging mapagkukunan. Mabibigo ang mga pagtatangka ng iba pang mga thread (mga tao) na makakuha ng access sa mga nasasakupang mapagkukunan. Ang isang mutex ay may ilang mahahalagang katangian. Una , dalawang estado lang ang posible: "naka-unlock" at "naka-lock". Nakakatulong ito sa amin na maunawaan kung paano ito gumagana: maaari kang gumuhit ng mga parallel sa mga variable ng Boolean (true/false) o mga binary na numero (0/1). , hindi direktang makokontrol ang estado. Walang mekanismo ang Java na hahayaan kang tahasang kumuha ng isang bagay, makuha ang mutex nito, at italaga ang nais na katayuan. Sa madaling salita, hindi mo magagawa ang isang bagay tulad ng:

Object myObject = new Object();
Mutex mutex = myObject.getMutex();
mutex.free();
Nangangahulugan ito na hindi mo mailalabas ang mutex ng isang bagay. Tanging ang Java machine lamang ang may direktang access dito. Ang mga programmer ay nagtatrabaho sa mga mutex sa pamamagitan ng mga tool ng wika.

Subaybayan

Ang monitor ay isang karagdagang "superstructure" sa isang mutex. Sa katunayan, ang monitor ay isang tipak ng code na "hindi nakikita" ng programmer. Noong napag-usapan namin ang tungkol sa mga mutex kanina, nagbigay kami ng isang simpleng halimbawa:

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
       }
   }
}
Sa block ng code na minarkahan ng naka-synchronize na keyword, nakuha ang mutex ng aming obj object. Mahusay, maaari nating makuha ang lock, ngunit paano eksaktong ibinigay ang "proteksyon"? Kapag nakita natin ang salitang naka-synchronize , ano ang pumipigil sa ibang mga thread na makapasok sa block? Ang proteksyon ay nagmumula sa isang monitor! Kino-convert ng compiler ang naka-synchronize na keyword sa ilang espesyal na piraso ng code. Muli, bumalik tayo sa ating halimbawa gamit ang doSomething() na pamamaraan. Idagdag namin dito:

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();
       }
   }
}
Narito ang mangyayari "sa ilalim ng talukbong" pagkatapos i-convert ng compiler ang code na ito:

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;
   }
}
Siyempre, hindi ito isang tunay na halimbawa. Dito, ginamit namin ang Java-like na code upang ilarawan kung ano ang nangyayari sa loob ng Java machine. Iyon ay sinabi, ang pseudo-code na ito ay nagbibigay ng isang mahusay na pag-unawa sa kung ano ang aktwal na nangyayari sa bagay at mga thread sa loob ng naka-synchronize na bloke at kung paano kino-convert ng compiler ang keyword na ito sa ilang mga pahayag na "hindi nakikita" ng programmer. Karaniwan, ginagamit ng Java ang naka-synchronize na keyword upang kumatawan sa isang monitor . Ang lahat ng code na lumalabas sa halip na ang naka-synchronize na keyword sa huling halimbawa ay ang monitor.

Semaphore

Ang isa pang salita na makikita mo sa iyong personal na pag-aaral ng multithreading ay "semaphore". Alamin natin kung ano ito at kung paano ito naiiba sa isang monitor at isang mutex. Ang semaphore ay isang tool para sa pag-synchronize ng access sa ilang mapagkukunan. Ang natatanging tampok nito ay ang paggamit nito ng isang counter upang lumikha ng mekanismo ng pag-synchronize. Sinasabi sa amin ng counter kung gaano karaming mga thread ang maaaring sabay na ma-access ang nakabahaging mapagkukunan. Ano ang pagkakaiba sa pagitan ng isang mutex, isang monitor, at isang semaphore?  - 3Ang mga semaphore sa Java ay kinakatawan ng klase ng Semaphore . Kapag lumilikha ng mga bagay na semaphore, maaari naming gamitin ang mga sumusunod na konstruktor:

Semaphore(int permits)
Semaphore(int permits, boolean fair)
Ipinapasa namin ang sumusunod sa tagabuo:
    int permit — ang inisyal at pinakamataas na halaga ng counter. Sa madaling salita, tinutukoy ng parameter na ito kung gaano karaming mga thread ang maaaring sabay na ma-access ang nakabahaging mapagkukunan;
  • boolean fair — nagtatatag ng pagkakasunud-sunod kung saan magkakaroon ng access ang mga thread. Kung totoo ang patas, ibibigay ang access sa naghihintay na mga thread sa pagkakasunud-sunod kung saan nila ito hiniling. Kung ito ay mali, ang pagkakasunud-sunod ay tinutukoy ng thread scheduler.
Ang isang klasikong halimbawa ng paggamit ng semaphore ay ang problema ng pilosopo sa kainan. Ano ang pagkakaiba sa pagitan ng isang mutex, isang monitor, at isang semaphore?  - 4Upang mapadali ang pag-unawa, pasimplehin namin ito nang kaunti. Isipin na mayroon tayong 5 pilosopo na kailangang kumain ng tanghalian. Bukod pa rito, mayroon kaming isang mesa na maaaring sabay-sabay na tumanggap ng hindi hihigit sa dalawang tao. Ang aming gawain ay pakainin ang lahat ng mga pilosopo. Wala sa kanila ang dapat magutom, at wala sa kanila ang dapat "magharang" sa isa't isa kapag sinusubukang umupo sa mesa (kailangan nating iwasan ang deadlock). Narito ang magiging hitsura ng aming klase ng pilosopo:

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!");
       }
   }
}
At narito ang code upang patakbuhin ang aming programa:

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();
   }
}
Gumawa kami ng isang semaphore na ang counter ay nakatakda sa 2 upang matugunan ang kundisyon: dalawang pilosopo lang ang makakain nang sabay. Ibig sabihin, dalawang thread lang ang maaaring tumakbo nang sabay, dahil namamana ng klase ng Philosopher ang Thread ! Ang acquire() at release() na mga paraan ng Semaphore class ay kumokontrol sa access counter nito. Ang acquire() method ay humihingi sa semaphore ng access sa resource. Kung ang counter ay >0, ang pag-access ay ibibigay at ang counter ay mababawasan ng 1. Ang release()"pinakawalan" ng pamamaraan ang dating ibinigay na access, ibinabalik ito sa counter (tinataasan ng 1 ang access counter ng semaphore). Ano ang makukuha natin kapag pinapatakbo natin ang programa? Nalutas ba ang problema? Hindi ba lalaban ang ating mga pilosopo habang naghihintay sila ng kanilang turn? :) Narito ang console output na nakuha namin:

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 
Nagawa natin! At bagaman kinailangan ni Thales na kumain mag-isa, sa palagay ko ay hindi namin siya nasaktan :) Maaaring napansin mo ang ilang pagkakatulad sa pagitan ng isang mutex at isang semaphore. Sa katunayan, mayroon silang parehong misyon: upang i-synchronize ang pag-access sa ilang mapagkukunan. Ano ang pagkakaiba sa pagitan ng isang mutex, isang monitor, at isang semaphore?  - 5Ang pagkakaiba lang ay ang mutex ng isang bagay ay maaaring makuha ng isang thread lamang sa isang pagkakataon, habang sa kaso ng isang semaphore, na gumagamit ng thread counter, maraming mga thread ang maaaring ma-access ang mapagkukunan nang sabay-sabay. Hindi lang ito nagkataon :) Ang mutex ay talagang isang semaphorena may bilang na 1. Sa madaling salita, ito ay isang semaphore na kayang tumanggap ng isang thread. Kilala rin ito bilang isang "binary semaphore" dahil ang counter nito ay maaaring magkaroon lamang ng 2 value — 1 ("naka-unlock") at 0 ("naka-lock"). Ayan yun! Tulad ng nakikita mo, hindi ito nakakalito pagkatapos ng lahat :) Ngayon, kung gusto mong pag-aralan ang multithreading nang mas detalyado sa Internet, magiging mas madali para sa iyo na mag-navigate sa mga konseptong ito. Magkita-kita tayo sa susunod na mga aralin!
Mga komento
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION