דוגמה להמתנה, הודעה והודעה לכולם ב-Java Thread

המחלקה Object ב-Java מכילה שלושה שיטות סופיות שמאפשרות לתהליכים לתקשר לגבי מצב הנעילה של משאב. שלוש השיטות הם wait(), notify() ו־notifyAll(). אז היום נבחן את wait, notify ו־notifyAll בתכנית Java.

wait, notify ו־notifyAll ב-Java

התהליך הנוכחי שקורא לשיטות אלו על כל אובייקט צריך להחזיק ב־monitor של האובייקט אחרת יזריק חריגת java.lang.IllegalMonitorStateException.

wait

שיטות ההמתנה של Object יש להן שלושה וריאציות, אחת שמחכה לצמיגה לכל שאר התהליכים לקרוא לשיטת notify או notifyAll על האובייקט כדי להעיר את התהליך הנוכחי. שתי וריאציות נוספות מעבירות את התהליך הנוכחי למצב המתנה לזמן ספציפי לפני שהן מעירות אותו.

notify

עיקרון ה-notify מעיר רק את אחד התהליכים המחכים על האובייקט והתהליך הזה מתחיל להרצות. אז אם ישנם מספר רב של תהליכים המחכים לאובייקט, אז מתוך הם רק תהליך אחד יתעורר. בחירת התהליך המתעורר תלויה במימוש של מערכת ההתמקדות בתהליכים של מערכת ההפעלה.

notifyAll

שיטת notifyAll מעירה את כל התהליכים המחכים על האובייקט, אף שאילו מתוך הם יתמיד לתהליך ראשון לעבוד תלוי במימוש המערכת ההפעלה. שתי השיטות אלו יכולות לשמש ליישום של בעיה של בעיה של יצרן צרכן כאשר תהליכי הצרכן מחכים לאובייקטים בתוך התור ותהליכי היצרן מכניסים את האובייקטים לתור ומעירים את התהליכים המחכים. בואו נראה דוגמה בה תהליכים מרבים עובדים על אובייקט אחד ואנו משתמשים בשיטות wait, notify ו-notifyAll.

Message

A java bean class on which threads will work and call wait and notify methods.

package com.journaldev.concurrency;

public class Message {
    private String msg;
    
    public Message(String str){
        this.msg=str;
    }

    public String getMsg() {
        return msg;
    }

    public void setMsg(String str) {
        this.msg=str;
    }

}

Waiter

A class that will wait for other threads to invoke notify methods to complete it’s processing. Notice that Waiter thread is owning monitor on Message object using synchronized block.

package com.journaldev.concurrency;

public class Waiter implements Runnable{
    
    private Message msg;
    
    public Waiter(Message m){
        this.msg=m;
    }

    @Override
    public void run() {
        String name = Thread.currentThread().getName();
        synchronized (msg) {
            try{
                System.out.println(name+" waiting to get notified at time:"+System.currentTimeMillis());
                msg.wait();
            }catch(InterruptedException e){
                e.printStackTrace();
            }
            System.out.println(name+" waiter thread got notified at time:"+System.currentTimeMillis());
            //עיבוד ההודעה כעת
            System.out.println(name+" processed: "+msg.getMsg());
        }
    }

}

הודען

A class that will process on Message object and then invoke notify method to wake up threads waiting for Message object. Notice that synchronized block is used to own the monitor of Message object.

package com.journaldev.concurrency;

public class Notifier implements Runnable {

    private Message msg;
    
    public Notifier(Message msg) {
        this.msg = msg;
    }

    @Override
    public void run() {
        String name = Thread.currentThread().getName();
        System.out.println(name+" started");
        try {
            Thread.sleep(1000);
            synchronized (msg) {
                msg.setMsg(name+" Notifier work done");
                msg.notify();
                // msg.notifyAll();
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        
    }

}

WaitNotifyTest

מחלקת בדיקה שתיצור תהליכים מרובים של Waiter ו-Notifier ותפעיל אותם.

package com.journaldev.concurrency;

public class WaitNotifyTest {

    public static void main(String[] args) {
        Message msg = new Message("process it");
        Waiter waiter = new Waiter(msg);
        new Thread(waiter,"waiter").start();
        
        Waiter waiter1 = new Waiter(msg);
        new Thread(waiter1, "waiter1").start();
        
        Notifier notifier = new Notifier(msg);
        new Thread(notifier, "notifier").start();
        System.out.println("All the threads are started");
    }

}

כאשר נקרא לתוכנית מעלה, נקבל את הפלט הבא אך התוכנית לא תסיים מאחר וישנם שני תהליכים הממתינים על אובייקט ההודעה ושיטת ה-notify() העוררת רק אחד מהם, תהליך השני עדיין ממתין לקבלת הודעה.

waiter waiting to get notified at time:1356318734009
waiter1 waiting to get notified at time:1356318734010
All the threads are started
notifier started
waiter waiter thread got notified at time:1356318735011
waiter processed: notifier Notifier work done

אם נפסיק את הקריאה ל-notify() ונפתח את הקריאה ל-notifyAll() במחלקת ה-Notifier, התוצאה תהיה כדלקמן.

waiter waiting to get notified at time:1356318917118
waiter1 waiting to get notified at time:1356318917118
All the threads are started
notifier started
waiter1 waiter thread got notified at time:1356318918120
waiter1 processed: notifier Notifier work done
waiter waiter thread got notified at time:1356318918120
waiter processed: notifier Notifier work done

מאחר ושיטת notifyAll() מעירה את שני התהליכים של Waiter והתוכנית מסתיימת ומפסיקה לאחר ביצוע הרצתה. זהו כל הנושא של המתנה, התראה והתראה לכולם ב-Java.

Source:
https://www.digitalocean.com/community/tutorials/java-thread-wait-notify-and-notifyall-example