📜  Javanotify()和notifyAll()的区别

📅  最后修改于: 2021-09-11 06:24:23             🧑  作者: Mango

带有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

notify() 和 notifyAll() 的区别

  1. 通知线程数:我们可以使用 notify() 方法为一个等待特定对象的线程发出通知而通过 notifyAll() 方法,我们可以向特定对象的所有等待线程发出通知.
  2. 通过 JVM 通知线程:如果多个线程正在等待通知并且我们使用 notify() 方法,则只有一个线程收到通知,其余线程必须等待进一步的通知。哪个线程会收到我们无法预料的通知,因为它完全取决于 JVM。但是当我们使用notifyAll()方法时,多个线程得到了通知,但是线程的执行将一个一个地执行,因为线程需要锁并且一个对象只有一个锁可用。
  3. 线程的互换性:我们应该去通知()如果所有等待的线程是可以互换的(他们醒来的顺序并不重要)。一个常见的例子是线程池。但是我们应该将notifyAll() 用于等待线程可能具有不同目的并且应该能够并发运行的其他情况。一个例子是对共享资源的维护操作,其中多个线程在访问资源之前等待操作完成。

    何时使用 notify() 方法和 notifyAll()

    • 在互斥锁定的情况下,只有一个等待线程在收到通知后可以做一些有用的事情(在这种情况下获取锁)。在这种情况下,您宁愿使用 notify()。如果正确实施,您也可以在这种情况下使用 notifyAll() ,但是您会不必要地唤醒无论如何都无法执行任何操作的线程。
    • 在某些情况下,一旦等待完成,所有等待线程都可以采取有用的操作。一个例子是一组线程等待某个任务完成;任务完成后,所有等待的线程都可以继续其业务。在这种情况下,您将使用 notifyAll() 同时唤醒所有等待线程。

    notify() 和 notifyAll() 的应用

    • 对共享资源的维护操作,其中多个线程在访问资源之前等待操作完成;对于这些我们应该去notifyAll()。
    • 假设我们有一个生产者线程和一个消费者线程。生产者生产的每个“数据包”都应该被消费者消费。消费者将一些东西放入队列,然后调用notify()。
    • 我们希望在漫长的过程完成时收到通知。您需要提示音和屏幕更新。该进程执行notifyAll() 来通知哔哔线程和屏幕更新线程。

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