Java 線程wait, notify and notifyAll 示例

原文地址:http://www.journaldev.com/1037/java-thread-wait-notify-and-notifyall-example
Java的Object類提供了三個final方法來在維護多線程中資源的鎖狀態。它們是wait(), notify() 和 notifyAll()。使用這三個方法來維護資源的線程必須有該資源的monitor(使用synchronized關鍵字,譯者注),否則會拋出java.lang.IllegalMonitorStateException.
wait
對象的wait方法有三種調用方式,第一種當前線程會無限等待其他線程調用該對象的notify或者notifyAll方法來喚醒它所在的線程;另外兩個會令當前線程等待特定的時間然後喚醒。
notify
notify方法每次只喚醒一個等待該object的線程。所以如果多個線程在等待這個object,這個方法只會喚醒其中的一個。喚醒哪個取決於系統實現的線程管理器。
notifyAll
notifyAll方法喚醒等待該object的所有線程,哪個先喚醒取決於操作系統。
這些方法可以用來實現 producer-consumer-problem (生產者消費者問題),消費者線程等待隊列中的對象,生產者線程向隊列中放入對象並通知等待的線程。
讓我們看一個多線程操作同一個對象的例子。
Message
下面是一個java bean類,線程會調用這個類的wait和notify方法。
Message.java

package com.journaldev.concurrency;
public class Message {
    private String msg;
    public Message(String str){
        this.msg=str;
    }
    public String getMsg() {
        returnmsg;
    }
    public void setMsg(String str) {
        this.msg=str;
    }
}

Waiter
該類會等待別的線程調用notify方法來喚醒自己。注意Waiter線程使用synchronized 塊擁有了Message的monitor。

package com.journaldev.concurrency;
public class Waiter implements Runnable{
    private Message msg;
    public Waiter(Message m){
        this.msg=m;
    }
    @Override
    publicvoidrun() {
        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());
            //process the message now
            System.out.println(name+" processed: "+msg.getMsg());
        }
    }
}

Notifier
該類會對Message對象進行處理,然後調用notify方法來喚醒等待Message對象的線程。它同樣用synchronized塊擁有了對Message的管理。
Notifier.java

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線程和一個Notifer線程。
WaitNotifyTest.java

package com.journaldev.concurrency;
public class WaitNotifyTest {
    public static void main(String[] args) {
        Message msg = newMessage("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");
    }
}

運行上面的程序,會看到下面的運行結果,程序不會結束因爲有兩個線程在等待Message對象但是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()方法,會出現下面的運行結果。

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喚醒了所有的等待線程,程序結束。


譯者注:
1 有哪些更實際的例子呢?

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章