Java多線程中wait, notify and notifyAll的使用

原文:http://blog.csdn.net/luoweifu/article/details/46664809   講得很透徹,留檔學習。


本文爲翻譯文章,原文地址:http://www.journaldev.com/1037/java-thread-wait-notify-and-notifyall-example

在Java的Object類中有三個final的方法允許線程之間進行資源對象鎖的通信,他們分別是: wait(), notify() and notifyAll()。

調用這些方法的當前線程必須擁有此對象監視器,否則將會報java.lang.IllegalMonitorStateException exception異常。

wait

Object的wait方法有三個重載方法,其中一個方法wait() 是無限期(一直)等待,直到其它線程調用notify或notifyAll方法喚醒當前的線程;另外兩個方法wait(long timeout) 和wait(long timeout, int nanos)允許傳入 當前線程在被喚醒之前需要等待的時間,timeout爲毫秒數,nanos爲納秒數。

notify

notify方法只喚醒一個等待(對象的)線程並使該線程開始執行。所以如果有多個線程等待一個對象,這個方法只會喚醒其中一個線程,選擇哪個線程取決於操作系統對多線程管理的實現。

notifyAll

notifyAll 會喚醒所有等待(對象的)線程,儘管哪一個線程將會第一個處理取決於操作系統的實現。

這些方法可以使用於“生產者-消費者”問題,消費者是在隊列中等待對象的線程,生產者是在隊列中釋放對象並通知其他線程的線程。

讓我們來看一個多線程作用於同一個對象的例子,我們使用wait, notify and notifyAll方法。


通過實例來理解

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() {
        return msg;
    }

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

}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

Waiter

一個Waiter類,等待其它的線程調用notify方法以喚醒線程完成處理。注意等待線程必須通過加synchronized同步鎖擁有Message對象的監視器。

Waiter.java

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());
            //process the message now
            System.out.println(name+" processed: "+msg.getMsg());
        }
    }

}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27

Notifier

一個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();
        }

    }

}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28

WaitNotifyTest

一個測試類,交付創建多個等待線程和一個通過線程,並啓動這些線程。

WaitNotifyTest.java

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");
    }

}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

當我們調用以上的代碼時可以看到以下的輸出,但並沒有結束(完成),因爲有兩個線程等待同一個Message對象,但notify()方法只能喚醒一個線程,另一個線程仍然在等待被喚醒。

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 Notifying work done
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

如果我們註釋掉Notifier類中的notify() 方法的調用,並打開notifyAll() 方法的調用,將會有以下的輸出信息。

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 Notifying work done
waiter waiter thread got notified at time:1356318918120
waiter processed: notifier Notifying work done
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

一旦notifyAll()方法喚醒所有的Waiter線程,程序將會執行完成並退出。


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