1. 程式人生 > >最簡例項說明WAIT、NOTIFY、NOTIFYALL的使用方法

最簡例項說明WAIT、NOTIFY、NOTIFYALL的使用方法

wait()、notify()、notifyAll()是三個定義在Object類裡的方法,可以用來控制執行緒的狀態。

這三個方法最終呼叫的都是jvm級的native方法。隨著jvm執行平臺的不同可能有些許差異。
    如果物件呼叫了wait方法就會使持有該物件的執行緒把該物件的控制權交出去,然後處於等待狀態。
    如果物件呼叫了notify方法就會通知某個正在等待這個物件的控制權的執行緒可以繼續執行。
    如果物件呼叫了notifyAll方法就會通知所有等待這個物件控制權的執行緒繼續執行。

其中wait方法有三個over load方法:
wait()
wait(long)
wait(long,int)
wait方法通過引數可以指定等待的時長。如果沒有指定引數,預設一直等待直到被通知。

以下是一個演示程式碼,以最簡潔的方式說明覆雜的問題:
簡要說明下:
NotifyThread是用來模擬3秒鐘後通知其他等待狀態的執行緒的執行緒類;
WaitThread是用來模擬等待的執行緒類;
等待的中間物件是flag,一個String物件;
main方法中同時啟動一個Notify執行緒和三個wait執行緒;

    public class NotifyTest {  
        private  String flag = "true";  
      
        class NotifyThread extends Thread{  
            public NotifyThread(String name) {  
                super(name);  
            }  
            public void run() {       
                try {  
                    sleep(3000);//推遲3秒鐘通知  
                } catch (InterruptedException e) {  
                    e.printStackTrace();  
                }  
                  
                    flag = "false";  
                    flag.notify();  
            }  
        };  
      
        class WaitThread extends Thread {  
            public WaitThread(String name) {  
                super(name);  
            }  
      
            public void run() {  
                  
                    while (flag!="false") {  
                        System.out.println(getName() + " begin waiting!");  
                        long waitTime = System.currentTimeMillis();  
                        try {  
                            flag.wait();  
                        } catch (InterruptedException e) {  
                            e.printStackTrace();  
                        }  
                        waitTime = System.currentTimeMillis() - waitTime;  
                        System.out.println("wait time :"+waitTime);  
                    }  
                    System.out.println(getName() + " end waiting!");  
                  
            }  
        }  
      
        public static void main(String[] args) throws InterruptedException {  
            System.out.println("Main Thread Run!");  
            NotifyTest test = new NotifyTest();  
            NotifyThread notifyThread =test.new NotifyThread("notify01");  
            WaitThread waitThread01 = test.new WaitThread("waiter01");  
            WaitThread waitThread02 = test.new WaitThread("waiter02");  
            WaitThread waitThread03 = test.new WaitThread("waiter03");  
            notifyThread.start();  
            waitThread01.start();  
            waitThread02.start();  
            waitThread03.start();  
        }  
      
    }

OK,如果你拿這段程式去執行下的話, 會發現根本執行不了,what happened?滿屏的java.lang.IllegalMonitorStateException。
沒錯,這段程式有很多問題,我們一個個來看。

首先,這兒要非常注意的幾個事實是
    任何一個時刻,物件的控制權(monitor)只能被一個執行緒擁有。
    無論是執行物件的wait、notify還是notifyAll方法,必須保證當前執行的執行緒取得了該物件的控制權(monitor)
    如果在沒有控制權的執行緒裡執行物件的以上三種方法,就會報java.lang.IllegalMonitorStateException異常。
    JVM基於多執行緒,預設情況下不能保證執行時執行緒的時序性

基於以上幾點事實,我們需要確保讓執行緒擁有物件的控制權。
也就是說在waitThread中執行wait方法時,要保證waitThread對flag有控制權;
在notifyThread中執行notify方法時,要保證notifyThread對flag有控制權。
執行緒取得控制權的方法有三:
    執行物件的某個同步例項方法。
    執行物件對應類的同步靜態方法。
    執行對該物件加同步鎖的同步塊。
我們用第三種方法來做說明:
將以上notify和wait方法包在同步塊中

synchronized (flag) {  
                flag = "false";  
                flag.notify();  
            }
synchronized (flag) {  
                while (flag!="false") {  
                    System.out.println(getName() + " begin waiting!");  
                    long waitTime = System.currentTimeMillis();  
                    try {  
                        flag.wait();  
                    } catch (InterruptedException e) {  
                        e.printStackTrace();  
                    }  
                    waitTime = System.currentTimeMillis() - waitTime;  
                    System.out.println("wait time :"+waitTime);  
                }  
                System.out.println(getName() + " end waiting!");  
            }

我們向前進了一步。
問題解決了嗎?
好像執行還是報錯java.lang.IllegalMonitorStateException。what happened?

這時的異常是由於在針對flag物件同步塊中,更改了flag物件的狀態所導致的。如下:
flag=”false”;
flag.notify();
對在同步塊中對flag進行了賦值操作,使得flag引用的物件改變,這時候再呼叫notify方法時,因為沒有控制權所以丟擲異常。
我們可以改進一下,將flag改成一個JavaBean,然後更改它的屬性不會影響到flag的引用。
我們這裡改成陣列來試試,也可以達到同樣的效果:

這時候再執行,不再報異常,但是執行緒沒有結束是吧,沒錯,還有執行緒堵塞,處於wait狀態。
原因很簡單,我們有三個wait執行緒,只有一個notify執行緒,notify執行緒執行notify方法的時候,是隨機通知一個正在等待的執行緒,所以,現在應該還有兩個執行緒在waiting。
我們只需要將NotifyThread執行緒類中的flag.notify()方法改成notifyAll()就可以了。notifyAll方法會通知所有正在等待物件控制權的執行緒。
 最終完成版如下:

public class NotifyTest {  
    private String flag[] = { "true" };  
  
    class NotifyThread extends Thread {  
        public NotifyThread(String name) {  
            super(name);  
        }  
  
        public void run() {  
            try {  
                sleep(3000);  
            } catch (InterruptedException e) {  
                e.printStackTrace();  
            }  
            synchronized (flag) {  
                flag[0] = "false";  
                flag.notifyAll();  
            }  
        }  
    };  
  
    class WaitThread extends Thread {  
        public WaitThread(String name) {  
            super(name);  
        }  
  
        public void run() {  
            synchronized (flag) {  
                while (flag[0] != "false") {  
                    System.out.println(getName() + " begin waiting!");  
                    long waitTime = System.currentTimeMillis();  
                    try {  
                        flag.wait();  
  
                    } catch (InterruptedException e) {  
                        e.printStackTrace();  
                    }  
                    waitTime = System.currentTimeMillis() - waitTime;  
                    System.out.println("wait time :" + waitTime);  
                }  
                System.out.println(getName() + " end waiting!");  
            }  
        }  
    }  
  
    public static void main(String[] args) throws InterruptedException {  
        System.out.println("Main Thread Run!");  
        NotifyTest test = new NotifyTest();  
        NotifyThread notifyThread = test.new NotifyThread("notify01");  
        WaitThread waitThread01 = test.new WaitThread("waiter01");  
        WaitThread waitThread02 = test.new WaitThread("waiter02");  
        WaitThread waitThread03 = test.new WaitThread("waiter03");  
        notifyThread.start();  
        waitThread01.start();  
        waitThread02.start();  
        waitThread03.start();  
    }  
  
}

相關推薦

例項說明WAITNOTIFYNOTIFYALL的使用方法

wait()、notify()、notifyAll()是三個定義在Object類裡的方法,可以用來控制執行緒的狀態。 這三個方法最終呼叫的都是jvm級的native方法。隨著jvm執行平臺的不同可能有些許差異。     如果物件呼叫了wait方法就會使持有該物件的執行緒

【併發程式設計】Object的waitnotifynotifyAll方法

本部落格系列是學習併發程式設計過程中的記錄總結。由於文章比較多,寫的時間也比較散,所以我整理了個目錄貼(傳送門),方便查閱。 併發程式設計系列部落格傳送門 方法簡介 wait方法 wait方法是Object類中的一個方法。呼叫這個方法會讓呼叫執行緒進入waiting狀態,直到另一個執行緒呼叫了當前物件上的

實例說明waitnotifynotifyAll的使用方法

strong rup 獲取對象 nat int clas java 基礎 long lag synchorize方法或獲取對象內部的鎖,之後可以對對象做wait,notify,notifyAll操作。 condition是與lock關聯的,對condition做sin

Java並發之線程間協作Object的wait()notify()notifyAll()

它的 ring sleep方法 子類 string exce 程序退出 data- 差異 wait()、notify()和notifyAll()是Object類中的方法: 1)wait()、notify()和notifyAll()方法是本地方法,而且為fina

Java並發編程:線程間協作的兩種方式:waitnotifynotifyAll和Condition

消費者 CI 能夠 .com stat consumer 使用 producer imp 原文鏈接 Java並發編程:線程間協作的兩種方式:wait、notify、notifyAll和Condition 在前面我們將了很多關於同步的問題,然而在現實中,需要線程之間的協作。比

線程間協作:waitnotifynotifyAll

runtime 對象 中一 全部 才會 stat 之前 monitors 中斷 線程間協作:wait、notify、notifyAll 在 Java 中,可以通過配合調用 Object 對象的 wait() 方法和 notify()方法或 notifyAll() 方法

JAVA執行緒間協作waitnotifynotifyAllsleep用途

在上節中,介紹了java多執行緒中同步鎖的概念,synchronized方法和synchronized程式碼塊都是為了解決執行緒併發的問題,同一時間允許一個執行緒訪問當前類或者物件。如果涉及到執行緒間的協作通訊,就需要用到wait、notify、notifyAll方法,這三個方法是Object的

waitnotifynotifyAll和Condition

轉自  http://www.cnblogs.com/dolphin0520/p/3920385.html 用來學習記錄              可以用最經典的生產者-消費者模型:當佇列滿時,生產者需要等

wait()notify()notifyAll() sleep()的注意點

參考:https://blog.csdn.net/u014561933/article/details/58639411 參考:Java併發程式設計藝術 P98 wait補充知識點:有且只能呼叫持有鎖對應的物件的wait方法。若持有的是當前執行緒物件的鎖,則可以直接呼叫wait()/t

waitnotifynotifyAll

標註的解釋 /** * Wakes up a single thread that is waiting on this object's * monitor. If any threads are waiting on this object, one of them

wait()notify()notifyAll()與執行緒通訊方式總結

1、通過wait()、notify()、notifyAll()進行執行緒通訊 執行緒通訊的目標是使執行緒間能夠互相傳送訊號。另一方面,執行緒通訊使執行緒能夠等待其他執行緒的訊號。例如,執行緒B可以等待執行緒A的一個訊號,這個訊號會通知執行緒B資料已經準備好了。 Java有一個內建的等待機制來允許執行

#Java多執行緒知識點總結waitnotifynotifyAll

Java多執行緒 設計一個典型的場景,來闡述wait()、notify()、notifyAll(),生產消費者。 有生產者、消費者、緩衝佇列(size=10)。 生產者不停地向緩衝佇列裡放資料,一旦佇列滿了,則wait(),並notify()消費者進行處理。 消費者不停地從緩衝佇列裡

java併發——wait()notify()notifyAll()join()

鎖池和等待池 wait() ,notifyAll(),notify() 三個方法都是Object類中的方法。學習他們之前先要了解倆個概念。java中,每個物件都有兩個池,鎖(monitor)池和等待池。 鎖池:假設執行緒A已經擁有了某個物件(注意:不

17-Java併發程式設計:執行緒間協作的兩種方式:waitnotifynotifyAll和Condition

Java併發程式設計:執行緒間協作的兩種方式:wait、notify、notifyAll和Condition   在前面我們將了很多關於同步的問題,然而在現實中,需要執行緒之間的協作。比如說最經典的生產者-消費者模型:當佇列滿時,生產者需要等待佇列有空間才能繼續往裡面放

多執行緒通訊(waitnotifyLockThreadLocal)

多執行緒之間通訊 什麼是多執行緒通訊? 就是多個執行緒對同一個共享資源,進行不同的操作。 介紹兩個API中的方法,這兩個是Object裡面的方法: wait();等待,執行緒從執行狀態變為休眠狀態 notify();喚醒,執行緒從休眠狀態變為執行狀態 現在解決一下這樣一個案例: 兩個執行緒,面向一個倉庫進行

Java併發程式設計:執行緒間協作的兩種方式:waitnotifynotifyAll和Condition

在前面我們將了很多關於同步的問題,然而在現實中,需要執行緒之間的協作。比如說最經典的生產者-消費者模型:當佇列滿時,生產者需要等待佇列有空間才能繼續往裡面放入商品,而在等待的期間內,生產者必須釋放對臨界資源(即佇列)的佔用權。因為生產者如果不釋放對臨界資源的佔用權,那麼消費者

waitnotifynotifyAll的深入理解

Java多執行緒的wait和notify/notifyAll方法是成對出現和使用的,要執行這兩個方法,有一個前提就是,當前執行緒必須獲取其物件的鎖,否則會丟擲IllegalMonitorStateException,所以這兩個方法必須在同步塊程式碼中呼叫。生產者消費者模型是學習多執行緒知識中一個經典案例,一個

Thread之七:Object裡的waitnotifynotifyAll的使用方法

wait()、notify()、notifyAll()是三個定義在Object類裡的方法,可以用來控制執行緒的狀態 public final native void notify(); public final native void notifyAll(); public final na

Java多執行緒--同步與死鎖:synchronized;等待與喚醒:waitnotifynotifyAll;生命週期

class Info{ // 定義資訊類 private String name = "李興華"; // 定義name屬性 private String content = "JAVA講師" ; // 定義content屬性 private boolean flag = false ; // 設

JAVA多執行緒:執行緒間通訊(waitnotifynotifyAllwait set自定義鎖 BooleanLock )

       我們在開發多執行緒程式的時候,往往不會只存在一個獨立的執行緒,相反大多數情況下是需要多個執行緒之間進行協同工作的,如何在多個執行緒之間進行通訊,是本章學習的重點。另外,本章的最後部分將會分析synchronized關鍵字的缺陷,我們手動實現了一個