Java中notify()和notifyAll()的区别
带有 wait() 方法的notify()和notifyAll()方法用于线程之间的通信。通过调用 wait() 方法进入等待状态的线程将一直等待状态,直到任何其他线程在同一对象上调用 notify() 或 notifyAll() 方法。
notify(): notify() 方法定义在Object 类中,该类是Java 的顶级类。它用于只唤醒一个正在等待对象的线程,然后该线程开始执行。线程类 notify() 方法用于唤醒单个线程。
notifyAll(): notifyAll() 唤醒所有在这个对象的监视器上等待的线程。线程通过调用其中一个等待方法在对象的监视器上等待。在当前线程放弃对该对象的锁定之前,被唤醒的线程将无法继续。
现在的问题是 notify() 和 notifyAll() 方法都用于向等待线程发出通知,那么它们之间有什么区别或者我们应该在哪里使用 notify() 方法以及我们应该在哪里使用 notifyAll()方法?
Sr. No. | Key | notify() | notifyAll() |
---|---|---|---|
1 | Notifications | In the case of the multiThreading, notify() method sends the notification to only one thread among the multiple waiting threads which are waiting for the send lock. | While notifyAll() methods in the same context send notifications to all waiting threads instead of a single thread. |
2 | Thread identifications | As in the case of notify() method, the notification is sent to a single thread among the multiple waiting threads, so it is sure that which of those waiting threads is going to receive the lock. | On the other hand, notifyAll() sends a notification to all waiting threads. Hence, it is not clear which of the thread is going to receive the lock. |
3 | Risk factor | In the case of notify() method, the risk of thread missing is high as notification is sent only a single thread, and if it misses that, then no other thread would get a notification and hence the lock. | While in the case of notifyAll(), it sends a notification to all the waiting threads, and hence if any thread misses the notification, there are other threads to do the job. Hence the risk is less. |
4 | Performance | Memory and CPU drain is less in notify() method as compared to notifyAll() method as notification is sent to single one thread so performance is better as compared to notifyAll(). | On the other hand, the cost of no notification is dropped and notification is sent to all waiting threads, the memory and CPU drain is more as compared to notify() and hence performance of notifyAll() is lesser. |
5 | Interchangeable | In the case of the notify() method, only a single thread is in the picture hence no concept of thread Interchangeable is possible. | While we should go for notifyAll() if all your waiting threads are interchangeable (the order they wake up doesn’t matter). |
让我们了解 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();
}
}
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...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
何时使用 notify() 方法和 notifyAll()?
- 在互斥锁的情况下,只有一个等待线程在收到通知后可以做一些有用的事情(在这种情况下获取锁)。在这种情况下,您宁愿使用 notify()。如果实施得当,您也可以在这种情况下使用 notifyAll() ,但是您会不必要地唤醒无论如何不能做任何事情的线程。
- 在某些情况下,一旦等待完成,所有等待的线程都可以采取有用的行动。一个例子是一组等待某个任务完成的线程;一旦任务完成,所有等待的线程都可以继续他们的业务。在这种情况下,您将使用 notifyAll() 同时唤醒所有等待的线程。
notify() 和 notifyAll() 的应用
- 对共享资源的维护操作,其中多个线程在访问资源之前正在等待操作完成;对于这些,我们应该使用 notifyAll()。
- 假设我们有一个生产者线程和一个消费者线程。生产者产生的每个“数据包”都应该被消费者消费。消费者将某些东西放入队列,然后调用 notify()。
- 我们希望在漫长的过程完成时收到通知。您需要哔声和屏幕更新。该进程执行 notifyAll() 以通知蜂鸣线程和屏幕更新线程。