JavaRush /בלוג Java /Random-HE /מה ההבדל בין מוטקס, מוניטור וסמפור

מה ההבדל בין מוטקס, מוניטור וסמפור

פורסם בקבוצה
שלום! בזמן שלמדת ריבוי שרשורים ב-JavaRush, נתקלת לעתים קרובות במושגים של "מוטקס" ו"מוניטור". האם אתה יכול עכשיו, בלי להציץ, לענות במה הם שונים? :) מה ההבדל בין מוטקס, מוניטור וסמפור - 1אם אתה יכול, כל הכבוד! אם לא (ולרוב זה קורה) - לא פלא. המושגים של "מוטקס" ו"מוניטור" אכן קשורים זה לזה. יתרה מכך, בזמן קריאת הרצאות וצפייה בסרטונים על ריבוי שרשורים במשאבים חיצוניים באינטרנט, תתקלו במושג דומה נוסף - "סמפורה". גם הפונקציונליות שלו דומה במידה רבה למוניטור ולמוטקס. לכן, בואו נבין את שלושת המונחים הללו, נסתכל על כמה דוגמאות ולבסוף נארגן בראשנו את ההבנה כיצד הם שונים זה מזה :)

מנעול

mutex הוא אובייקט מיוחד לסנכרון שרשורים. זה "מצורף" לכל אובייקט ב-Java - אתה כבר יודע את זה :) זה לא משנה אם אתה משתמש במחלקות סטנדרטיות או יצרת מחלקות משלך, נגיד, Catו Dog: לכל האובייקטים של כל המחלקות יש mutex . השם "mutex" מגיע מהאנגלית "MUTual EXclusion" - "הדרה הדדית", וזה משקף בצורה מושלמת את מטרתו. כפי שאמרנו באחת ההרצאות הקודמות, המשימה של mutex היא לספק מנגנון כזה, כך שלחוט אחד בלבד תהיה גישה לאובייקט בזמן מסוים . אנלוגיה פופולרית בחיים האמיתיים ל-mutex היא "דוגמה לשירותים". כשאדם נכנס לשירותים, הוא נועל את הדלת מבפנים. האסלה פועלת כאובייקט שניתן לגשת אליו באמצעות חוטים מרובים. המנעול בדלת השירותים הוא תפקיד של מוטקס, והתור של אנשים בחוץ הוא תפקיד החוטים. המנעול בדלת הוא מוטקס לשירותים: הוא מבטיח שרק אדם אחד יכול להיות בפנים בכל פעם. מה ההבדל בין מוטקס, מוניטור וסמפור - 2במילים אחרות, רק שרשור אחד בכל פעם יכול לעבוד על משאבים משותפים. ניסיונות של שרשורים אחרים (אנשים) לגשת למשאבים תפוסים ייכשלו. למוטקס יש כמה תכונות חשובות. ראשית , רק שתי מדינות אפשריות - "חופשי" ו"עסוק". זה מקל על ההבנה כיצד זה עובד: ניתן לצייר מקבילות עם משתנים בוליאניים אמת/שקר או מערכת המספרים הבינארית 1/0. שנית , לא ניתן לשלוט ישירות במדינות. אין מנגנונים ב-Java שיאפשרו לך לקחת אובייקט במפורש, לקבל את המוטקס שלו ולהקצות לו את הסטטוס הרצוי. במילים אחרות, אתה לא יכול לעשות משהו כמו:
Object myObject = new Object();
Mutex mutex = myObject.getMutex();
mutex.free();
לפיכך, לא ניתן לשחרר את המוטקס של האובייקט. רק למכשיר Java יש גישה ישירה אליו. מתכנתים עובדים עם מוטקסים באמצעות כלי שפה.

צג

מוניטור הוא "תוספת" נוספת למוטקס. למעשה, הצג הוא פיסת קוד "בלתי נראה" למתכנת . דיברנו על המוטקס קודם לכן, הבאנו דוגמה פשוטה:
public class Main {

   private Object obj = new Object();

   public void doSomething() {

       //...some logic available to all threads

       synchronized (obj) {

           //logic that is only available to one thread at a time
       }
   }
}
בגוש הקוד שמסומן במילה synchronized, נקלט המוטקס של האובייקט שלנו obj. אוקיי, הלכידה מתרחשת, אבל איך בדיוק מושג "מנגנון ההגנה"? synchronizedלמה שרשורים אחרים לא יכולים להיכנס לתוך הבלוק כשהם רואים מילה ? המוניטור הוא שיוצר את מנגנון ההגנה! המהדר ממיר את המילה synchronizedלכמה פיסות קוד מיוחדות. שוב נחזור לדוגמה שלנו עם השיטה doSomething()ונוסיף לה:
public class Main {

   private Object obj = new Object();

   public void doSomething() {

       //...some logic available to all threads

       //logic that is only available to one thread at a time
       synchronized (obj) {

           /*выполнить важную работу, при которой доступ к an objectу
           должен быть только у одного потока*/
           obj.someImportantMethod();
       }
   }
}
הנה מה שיקרה "מתחת למכסה המנוע" של התוכנית שלנו לאחר שהמהדר ימיר את הקוד הזה:
public class Main {

   private Object obj = new Object();

   public void doSomething() throws InterruptedException {

       //...some logic available to all threads

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

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

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

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

       //освободить мьютекс an object
       obj.getMutex().isBusy() = false;
   }
}
הדוגמה, כמובן, לא אמיתית. כאן, באמצעות קוד דמוי Java, ניסינו לשקף את מה שקורה ברגע זה בתוך מכונת ה-Java. עם זאת, פסאודוקוד זה נותן הבנה מצוינת של מה שקורה בפועל עם האובייקט והחוטים בתוך הבלוק synchronizedוכיצד המהדר ממיר את המילה הזו למספר פקודות "בלתי נראות" למתכנת. בעיקרו של דבר, מוניטור ב-Java מתבטא באמצעות המילהsynchronized . כל הקוד שהופיע במקום המילה synchronizedבדוגמה האחרונה הוא המוניטור.

סֵמָפוֹר

מילה נוספת שנתקלת בה כשאתה לומד ריבוי שרשורים בעצמך היא "סמפורה". בואו להבין מה זה ואיך זה שונה ממוניטור ומוטקס. סמפור הוא אמצעי לסנכרון גישה למשאב. הייחודיות שלו היא שהוא משתמש במונה בעת יצירת מנגנון סנכרון. המונה מספר לנו כמה שרשורים יכולים לגשת בו זמנית למשאב משותף. מה ההבדל בין מוטקס, מוניטור וסמפור - 3סמפורים ב-Java מיוצגים על ידי המחלקה Semaphore. בעת יצירת אובייקטי סמפור, אנו יכולים להשתמש בבנאים הבאים:
Semaphore(int permits)
Semaphore(int permits, boolean fair)
אנחנו עוברים לבנאי:
  • int permits- ערך מונה ראשוני ומקסימלי. כלומר, כמה שרשורים יכולים לגשת בו-זמנית למשאב משותף;

  • boolean fair- כדי לקבוע את הסדר שבו האשכולות יקבלו גישה. אם fair= true , ניתנת גישה לשרשורים ממתינים בסדר שבו הם ביקשו זאת. אם הוא שקר , הסדר ייקבע על ידי מתזמן השרשור.

דוגמה קלאסית לשימוש בסמפור היא בעיית הפילוסופים של ארוחת הצהריים .
מה ההבדל בין מוטקס, מוניטור וסמפור - 4
נפשט מעט את תנאיו להבנה טובה יותר. תאר לעצמך שיש לנו 5 פילוסופים שצריכים ארוחת צהריים. יחד עם זאת, יש לנו שולחן אחד, ולא יותר משני אנשים יכולים להיות בו בו-זמנית. המשימה שלנו היא להאכיל את כל הפילוסופים. אף אחד מהם לא צריך להיות רעב, וגם לא צריך "לחסום" אחד את השני כאשר מנסים לשבת ליד השולחן (עלינו למנוע מבוי סתום). כך ייראה כיתת הפילוסופים שלנו:
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 ("What-то пошло не так!");
       }
   }
}
והנה הקוד להפעלת התוכנית שלנו:
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();
   }
}
יצרנו סמפור עם ספירה של 2 כדי לספק את התנאי שרק שני פילוסופים יכולים לאכול בו זמנית. כלומר, רק שני חוטים יכולים לעבוד בו-זמנית, מכיוון שהכיתה שלנו Philosopherעברה בירושה מ- Thread! המחלקה והשיטות שולטות במונה ההרשאות שלה acquire(). השיטה מבקשת הרשאה לגשת למשאב מהסמפור. אם מונה > 0, ההרשאה ניתנת והמונה מופחת ב-1. השיטה "משחררת" את ההרשאה שניתנה קודם לכן ומחזירה אותה למונה (מגדילה את מונה ההענקה של הסמפור ב-1). מה אנחנו מקבלים כשאנחנו מריצים את התוכנית? האם הבעיה נפתרה?האם הפילוסופים שלנו ילחמו בזמן שהם ממתינים לתורם? :) זה פלט הקונסולה שקיבלנו: סוקרטס מתיישב ליד השולחן אפלטון מתיישב ליד השולחן שסוקרטס אכל! הוא עוזב את השולחן אפלטון אכל! הוא עוזב את השולחן אריסטו מתיישב ליד השולחן פיתגורס מתיישב ליד השולחן שאריסטו אכל! הוא עוזב את השולחן שפיתגורס אכל! הוא עוזב את השולחן תאלס מתיישב ליד השולחן שתאלס אכל! הוא עוזב את השולחן, הצלחנו! ולמרות שתאלס היה צריך לסעוד לבד, אני חושב שהוא לא כועס עלינו :) אולי שמתם לב לכמה קווי דמיון בין מוטקס לסמפור. באופן כללי, יש להם אותה מטרה: לסנכרן גישה למשאב כלשהו. ההבדל היחיד הוא שניתן לרכוש את המוטקס של אובייקט רק על ידי חוט אחד בכל פעם, בעוד שבמקרה של סמפור, נעשה שימוש במונה חוטים, וכמה מהם יכולים לגשת למשאב בבת אחת. וזה לא רק דמיון מקרי :) למעשה, mutex הוא סמפור של מקום אחד . כלומר, מדובר בסמפור שהמונה שלו מוגדר בהתחלה ל-1. הוא נקרא גם "סמפור בינארי" כי למונה שלו יכולים להיות רק 2 ערכים - 1 ("פנוי") ו-0 ("עסוק"). זה הכל! כפי שאתה יכול לראות, התברר שהכל לא כל כך מבלבל :) עכשיו, אם אתה רוצה ללמוד את נושא ריבוי השרשורים בפירוט רב יותר באינטרנט, יהיה לך קצת יותר קל לנווט בין המושגים. נתראה בשיעורים הבאים! release()Semaphoreacquire()release()מה ההבדל בין מוטקס, מוניטור וסמפור - 5
הערות
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION