當前位置: 首頁>>代碼示例 >>用法及示例精選 >>正文


Java notify()和notifyAll()的區別用法及代碼示例


具有wait()方法的notify()和notifyAll()方法用於線程之間的通信。通過調用wait()方法進入等待狀態的線程將處於等待狀態,直到其他線程在同一對象上調用notify()或notifyAll()方法為止。
現在的問題是,既使用notify()方法又使用notifyAll()方法向等待的線程發出通知,那麽它們之間有什麽區別,或者我們應該在哪裏使用notify()方法,哪裏應該使用notifyAll()方法?
讓我們了解notify()方法的行為:

// Java program to illustrate the 
// behaviour of notify() method 
class Geek1 extends Thread { 
public void run() 
    { 
        synchronized(this) 
        { 
            System.out.println 
            (Thread.currentThread().getName() + "...starts"); 
            try { 
                this.wait(); 
            } 
            catch (InterruptedException e) { 
                e.printStackTrace(); 
            } 
            System.out.println 
            (Thread.currentThread().getName() + "...notified"); 
        } 
    } 
} class Geek2 extends Thread { 
    Geek1 geeks1; 
    Geek2(Geek1 geeks1) 
    { 
        this.geeks1 = geeks1; 
    } 
public void run() 
    { 
        synchronized(this.geeks1) 
        { 
            System.out.println 
            (Thread.currentThread().getName() + "...starts"); 
  
            try { 
                this.geeks1.wait(); 
            } 
            catch (InterruptedException e) { 
                e.printStackTrace(); 
            } 
            System.out.println 
            (Thread.currentThread().getName() + "...notified"); 
        } 
    } 
} class Geek3 extends Thread { 
    Geek1 geeks1; 
    Geek3(Geek1 geeks1) 
    { 
        this.geeks1 = geeks1; 
    } 
public void run() 
    { 
        synchronized(this.geeks1) 
        { 
            System.out.println 
            (Thread.currentThread().getName() + "...starts"); 
            this.geeks1.notify(); 
            System.out.println 
            (Thread.currentThread().getName() + "...notified"); 
        } 
    } 
} class MainClass { 
public static void main(String[] args) throws InterruptedException 
    { 
  
        Geek1 geeks1 = new Geek1(); 
        Geek2 geeks2 = new Geek2(geeks1); 
        Geek3 geeks3 = new Geek3(geeks1); 
        Thread t1 = new Thread(geeks1, "Thread-1"); 
        Thread t2 = new Thread(geeks2, "Thread-2"); 
        Thread t3 = new Thread(geeks3, "Thread-3"); 
        t1.start(); 
        t2.start(); 
        Thread.sleep(100); 
        t3.start(); 
    } 
}

輸出:

Thread-1...start
Thread-2...starts
Thread-3...starts
Thread-3...notified
Thread-1...notified

讓我們了解notifyAll()方法的行為:

// Java program to illustrate the 
// behavior of notifyAll() method 
class Geek1 extends Thread { 
public void run() 
    { 
        synchronized(this) 
        { 
            System.out.println 
            (Thread.currentThread().getName() + "...starts"); 
            try { 
                this.wait(); 
            } 
            catch (InterruptedException e) { 
                e.printStackTrace(); 
            } 
            System.out.println 
            (Thread.currentThread().getName() + "...notified"); 
        } 
    } 
} class Geek2 extends Thread { 
    Geek1 geeks1; 
    Geek2(Geek1 geeks1) 
    { 
        this.geeks1 = geeks1; 
    } 
public void run() 
    { 
        synchronized(this.geeks1) 
        { 
            System.out.println 
            (Thread.currentThread().getName() + "...starts"); 
  
            try { 
                this.geeks1.wait(); 
            } 
            catch (InterruptedException e) { 
                e.printStackTrace(); 
            } 
            System.out.println 
            (Thread.currentThread().getName() + "...notified"); 
        } 
    } 
} class Geek3 extends Thread { 
    Geek1 geeks1; 
    Geek3(Geek1 geeks1) 
    { 
        this.geeks1 = geeks1; 
    } 
public void run() 
    { 
        synchronized(this.geeks1) 
        { 
            System.out.println 
            (Thread.currentThread().getName() + "...starts"); 
  
            this.geeks1.notifyAll(); 
            System.out.println 
            (Thread.currentThread().getName() + "...notified"); 
        } 
    } 
} class MainClass { 
public static void main(String[] args) throws InterruptedException 
    { 
  
        Geek1 geeks1 = new Geek1(); 
        Geek2 geeks2 = new Geek2(geeks1); 
        Geek3 geeks3 = new Geek3(geeks1); 
        Thread t1 = new Thread(geeks1, "Thread-1"); 
        Thread t2 = new Thread(geeks2, "Thread-2"); 
        Thread t3 = new Thread(geeks3, "Thread-3"); 
        t1.start(); 
        t2.start(); 
        Thread.sleep(100); 
        t3.start(); 
    } 
}

輸出:

Thread-1...starts
Thread-2...starts
Thread-3...starts
Thread-3...notified
Thread-2...notified
Thread-1...notified

Differences between notify() and notifyAll()



  1. 線程數通知:我們可以使用notify()方法僅向一個正在等待特定對象的線程發出通知,而借助notifyAll()方法,我們可以將通知給予特定對象的所有等待線程。
  2. 通過JVM通知線程:如果有多個線程在等待通知,而我們使用notify()方法,則隻有一個線程得到通知,其餘線程則必須等待進一步的通知。哪個線程將收到我們無法預期的通知,因為它完全取決於JVM。但是,當我們使用notifyAll()方法時,會收到多個線程的通知,但是線程的執行將一個接一個地執行,因為線程需要鎖,並且一個對象隻能使用一個鎖。
  3. 線程的互換性:如果您所有的等待線程都可以互換(喚醒的順序無關緊要),我們應該使用notify()。一個常見的例子是線程池。但是,在其他情況下,等待線程可能具有不同的用途並且應該能夠並行運行,我們應該使用notifyAll()。一個示例是對共享資源的維護操作,其中多個線程在訪問該資源之前正在等待操作完成。
  4. When to use notify() method and notifyAll()

  • 在互斥鎖定的情況下,隻有一個等待線程在得到通知後可以做一些有用的事情(在這種情況下,獲取鎖定)。在這種情況下,您寧願使用notify()。正確實施後,您也可以在這種情況下使用notifyAll(),但是不必要地喚醒線程,它們無論如何都無法執行任何操作。
  • 在某些情況下,等待完成後,所有等待線程都可以采取有用的措施。一個示例是一組等待某個任務完成的線程。任務完成後,所有等待的線程都可以繼續其業務。在這種情況下,您將使用notifyAll()同時喚醒所有等待的線程。

Applications of notify() and notifyAll()

  • 對共享資源的維護操作,其中多個線程在訪問該資源之前正在等待操作完成;為此,我們應該選擇notifyAll()。
  • 假設我們有一個生產者線程和一個消費者線程。生產者生產的每個“packet”應該由消費者消費。消費者將某些東西放入隊列中,然後調用notify()。
  • 冗長的過程完成後,我們希望收到通知。您需要發出嗶聲和屏幕更新。該過程執行notifyAll()以通知beeping-thread和screen-update-thread。

參考:https://stackoverflow.com/questions/37026/java-notify-vs-notifyall-all-over-again

相關用法


注:本文由純淨天空篩選整理自GeeksforGeeks大神的英文原創作品 Difference between notify() and notifyAll() in Java。非經特殊聲明,原始代碼版權歸原作者所有,本譯文未經允許或授權,請勿轉載或複製。