notify() 和notifyAll() 方法以及wait() 方法用於線程之間的通信。通過調用 wait() 方法進入等待狀態的線程將處於等待狀態,直到任何其他線程在同一對象上調用 notify() 或 notifyAll() 方法。
notify(): notify()方法定義在對象類,這是Java的頂級類。它隻用於喚醒一個線它正在等待一個對象,然後該線程開始執行。線程類notify()方法用於喚醒單個線程。
notifyAll():notifyAll() 喚醒在此對象監視器上等待的所有線程。線程通過調用其中之一來等待對象的監視器等待方法。被喚醒的線程將無法繼續,直到當前線程放棄該對象上的鎖。
現在的問題是notify()和notifyAll()方法都用於向等待線程發出通知,那麽它們之間有什麽區別或者我們應該在哪裏使用notify()方法以及我們應該在哪裏使用notifyAll()方法?
先生。沒有。 | 鑰匙 | notify() | notifyAll() |
---|---|---|---|
1 | Notifications | 在 multiThreading 的情況下,notify() 方法僅將通知發送到等待發送鎖的多個等待線程中的一個線程。 | 而同一上下文中的 notifyAll() 方法將通知發送給所有等待線程而不是單個線程。 |
2 | 線程標識 | 與notify()方法的情況一樣,通知被發送到多個等待線程中的單個線程,因此可以確定哪些等待線程將接收鎖。 | 另一方麵,notifyAll() 向所有等待線程發送通知。因此,不清楚哪個線程將接收鎖。 |
3 | 風險因子 | 在notify()方法的情況下,線程丟失的風險很高,因為通知僅發送給單個線程,如果它丟失了,那麽其他線程將不會收到通知,從而獲得鎖。 | 而在 notifyAll() 的情況下,它會向所有等待線程發送通知,因此如果任何線程錯過了通知,就會有其他線程來完成這項工作。因此風險較小。 |
4 | Performance | 與 notifyAll() 方法相比,Memory 和 CPU 在 notify() 方法中消耗更少,因為通知發送到單個線程,因此與 notifyAll() 相比性能更好。 | 另一方麵,沒有通知的成本被降低,通知被發送到所有等待線程,與 notify() 相比,內存和 CPU 消耗更多,因此 notifyAll() 的性能較低。 |
5 | Interchangeable | 在notify()方法的情況下,圖中隻有一個線程,因此不可能存在線程可互換的概念。 | 如果所有等待線程都可以互換(它們喚醒的順序並不重要),那麽我們應該選擇notifyAll()。 |
讓我們了解notify()方法的行為方式:
Java
// 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
// 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-1...notified Thread-2...notified
When to Use notify() method and notifyAll()?
- 在互斥鎖定的情況下,隻有一個等待線程在收到通知後可以執行一些有用的操作(在本例中獲取鎖)。在這種情況下,您寧願使用notify()。如果實現得當,您也可以在這種情況下使用notifyAll(),但您會不必要地喚醒無論如何都無法執行任何操作的線程。
- 在某些情況下,一旦等待完成,所有等待線程都可以采取有用的操作。一個例子是一組線程等待某個任務完成;一旦任務完成,所有等待線程就可以繼續其業務。在這種情況下,您可以使用notifyAll()同時喚醒所有等待線程。
Applications of notify() and notifyAll()
- 對共享資源的維護操作,其中多個線程在訪問資源之前等待操作完成;對於這些,我們應該選擇notifyAll()。
- 假設我們有一個生產者線程和一個消費者線程。生產者生產的每個 “packet” 都應該由消費者消費。消費者將一些東西放入隊列中,然後調用notify()。
- 我們希望在漫長的過程完成時收到通知。您需要蜂鳴聲和屏幕更新。該進程執行notifyAll()來通知蜂鳴線程和screen-update-thread。
相關用法
- Java notify()和notifyAll()的區別用法及代碼示例
- Java next()和nextLine()的區別用法及代碼示例
- Java String compareToIgnoreCase()用法及代碼示例
- Java String compareTo()用法及代碼示例
- Java String split()用法及代碼示例
- Java String length()用法及代碼示例
- Java String replace()用法及代碼示例
- Java String replaceAll()用法及代碼示例
- Java String substring()用法及代碼示例
- Java String equals()用法及代碼示例
- Java String equalsIgnoreCase()用法及代碼示例
- Java String contains()用法及代碼示例
- Java String indexOf()用法及代碼示例
- Java String trim()用法及代碼示例
- Java String charAt()用法及代碼示例
- Java String toLowerCase()用法及代碼示例
- Java String concat()用法及代碼示例
- Java String valueOf()用法及代碼示例
- Java String matches()用法及代碼示例
- Java String startsWith()用法及代碼示例
- Java String endsWith()用法及代碼示例
- Java String isEmpty()用法及代碼示例
- Java String intern()用法及代碼示例
- Java String getBytes()用法及代碼示例
- Java String contentEquals()用法及代碼示例
注:本文由純淨天空篩選整理自佚名大神的英文原創作品 Difference Between notify() and notifyAll() in Java。非經特殊聲明,原始代碼版權歸原作者所有,本譯文未經允許或授權,請勿轉載或複製。