wait、notify和notifyAll的關係

innoyiya發表於2018-01-30

以下兩個是Java提供用於協調執行緒之間的操作介面,並且是定義在Object中:

public final void wait() throws InterruptedException public final native void notify()

此兩個方法的呼叫必須先獲取監視器,即在synchronzied語句中呼叫。

必須使用鎖來呼叫方法,否則會出現 IllegalMonitorStateException 異常

因為一個執行緒在呼叫object.wait()後會釋放所持有的監視器,並進入等待佇列中。 而另一條執行緒在呼叫object.notify()後需該執行緒釋放所持有的鎖後被喚醒的執行緒才能爭奪到鎖資源繼續工作。

public class MyStack1 {
    private static final Object lock = new Object();
    public static class Producer extends Thread {
        @Override
        public void run() {
            synchronized (lock) {
                System.out.println(System.currentTimeMillis() + ": producer start!");
                try {
                    System.out.println(System.currentTimeMillis() + ": producer wait!");
                    lock.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(System.currentTimeMillis() + ": producer shop!");
            }
        }
    }

    public static class Consumer extends Thread {
        @Override
        public void run() {
            synchronized (lock) {
                System.out.println(System.currentTimeMillis() + ": consumer start and notify producer");
                lock.notify();
                System.out.println(System.currentTimeMillis() + ": consumer shop!");
                try {
                    //讓結果的時間戳更容易觀察
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }
    public static void main(String args[]) throws InterruptedException {
        Thread producer = new Producer();
        Thread consumer = new Consumer();
        producer.start();
        //這裡是為了讓producer先執行
        Thread.sleep(2000);
        consumer.start();
    }
}
複製程式碼
1517143096608: producer start!
1517143096608: producer wait!
1517143098621: consumer start and notify producer
1517143098621: consumer shop!
1517143099629: producer shop!
複製程式碼

當執行緒producer呼叫wait() 後會釋放鎖資源並進入等待佇列中進行等待。

隨後Consumer呼叫notify()後就會喚醒等待佇列中的執行緒,如果等待佇列中有多條執行緒則由執行緒規劃器隨機挑選喚醒。呼叫此方法不會釋放鎖資源。

被喚醒的執行緒會等待其他執行緒釋放鎖資源(如呼叫notify()的執行緒),之後只有獲取到鎖後才能繼續執行下去。

接下來是notifyAll():

public final native void notifyAll()

notify() 一次只能隨機叫醒一個人,而notifyAll() 卻能炸醒所有人。

與notify() 的差異在與notifyAll() 是一次性將在等待佇列中的所有執行緒全部喚醒,然後讓被喚醒執行緒們進行爭奪鎖資源。

相關文章