Java中notify()和 notifyAll()的区别

Java中notify()和 notifyAll()的区别

带有 wait() 方法的 notify()notifyAll() 方法用于线程之间的通信。 通过调用 wait() 方法进入等待状态的线程将一直处于等待状态,直到任何其他线程在同一对象上调用 notify()notifyAll() 方法。

notify(): notify() 方法定义在 Object 类中,该类是 Java 的顶级类。 它仅用于唤醒一个正在等待对象的线程,然后该线程开始执行。 线程类 notify() 方法用于唤醒单个线程。
notifyAll(): notifyAll() 唤醒所有在这个对象的监视器上等待的线程。 线程通过调用其中一个等待方法在对象的监视器上等待。 在当前线程放弃对该对象的锁定之前,被唤醒的线程将无法继续。
Java中notify()和 notifyAll()的区别

问题是 notify()notifyAll() 方法都用于向等待线程发出通知,那么它们之间有什么区别或者我们应该在哪里使用 notify() 方法和 notifyAll() 方法?

编号 比较项 notify() notifyAll()
1 通知 在多线程的情况下,notify() 方法只向等待发送锁的多个等待线程中的一个线程发送通知。 而同一上下文中的 notifyAll() 方法将通知发送到所有等待线程而不是单个线程。
2 线程标识 与notify()方法的情况一样,通知被发送到多个等待线程中的单个线程,因此可以确定那些等待线程中的哪一个将接收锁。 notifyAll() 向所有等待的线程发送通知。因此,不清楚哪个线程将接收锁。
3 风险因素 在 notify() 方法的情况下,线程丢失的风险很高,因为通知只发送一个线程,如果它错过了,那么其他线程将不会收到通知并因此锁定。 而在 notifyAll() 的情况下,它会向所有等待的线程发送通知,因此如果任何线程错过了通知,则还有其他线程来完成这项工作。因此风险较小。
4 性能 notify() 方法与 notifyAll() 方法相比,内存和 CPU 消耗更少,因为通知发送到单个线程,因此与 notifyAll() 相比,性能更好。 没有通知的成本被丢弃,通知被发送到所有等待的线程,内存和 CPU 消耗比 notify() 更多,因此 notifyAll() 的性能更稍差。
5 Interchangeable 在 notify() 方法的情况下,图中只有一个线程,因此不可能有 thread Interchangeable 的概念。 如果所有等待线程都是可互换的(它们唤醒的顺序无关紧要),应该使用 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-1...notified
Thread-2...notified

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

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

notify() 和 notifyAll() 的应用

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

Python教程

Java教程

Web教程

数据库教程

图形图像教程

大数据教程

开发工具教程

计算机教程