Разница между wait () и notifyall () в Java

Опубликовано: 30 Ноября, 2021

Многопоточность - это функция Java, которая позволяет одновременное выполнение двух или более частей программы для максимального использования ЦП. Каждая часть такой программы называется потоком. Итак, потоки - это легковесные процессы внутри процесса. Многопоточные программы часто могут доходить до ситуации, когда несколько потоков пытаются получить доступ к одним и тем же ресурсам и в конечном итоге дают ошибочные результаты.

Поэтому с помощью некоторого метода синхронизации необходимо убедиться, что только один поток может получить доступ к ресурсу в заданный момент времени. Java предоставляет способ создания потоков и синхронизации их задач с помощью синхронизированных блоков. Синхронизированные блоки в Java помечаются ключевым словом synchronized. Синхронизированный блок в Java синхронизируется на каком-то объекте. Все синхронизированные блоки, синхронизированные с одним и тем же объектом, могут иметь только один поток, выполняющийся внутри них одновременно.

Мы обсудим различия позже, давайте взглянем, как они взаимосвязаны, обсудив их индивидуально следующим образом:

  1. wait () Метод
  2. notifyAll () Метод

1. Метод wait ()

В многопоточности два потока могут обмениваться данными между потоками друг с другом с помощью метода wait (). Поток, ожидающий обновления, отвечает за вызов метода wait (), после чего поток немедленно переходит в состояние ожидания. Метод wait () присутствует в классе java.lang.Object, а не в классе Thread, потому что поток может вызывать этот метод для любого объекта java. Для вызова метода wait () любого java-объекта поток должен быть владельцем этого объекта, т. Е. Поток должен иметь блокировку этого объекта, т. Е. Поток должен находиться внутри синхронизированной области. Следовательно, мы можем вызвать метод wait () только из синхронизированной области, иначе мы получим исключение RuntimeException с сообщением IllegalMonitorStateException. Если поток вызывает метод wait () для любого объекта, он немедленно снимает блокировку этого конкретного объекта и переходит в состояние ожидания.

Синтаксис:

 public final void wait ()

Вышеупомянутый метод заставляет текущий поток ждать бесконечно, пока notify () или notifyAll () не вызовет для этого объекта.

 public final native void wait (длинная микросекунда)
 публичное окончательное недействительное ожидание (длинная микросекунда, интервал наносекунды)

Используя два вышеуказанных метода, мы можем указать тайм-аут, по истечении которого поток будет автоматически пробуждаться. Мы можем разбудить поток до истечения времени ожидания, используя метод notify () или notifyAll ().

Note: Do remember that every wait() method throws InterruptedException which is a checked exception hence whenever we are using the wait() method compulsory we should handle this  InterruptedException either by try-catch or by throws keyword otherwise we will get compile-time  error.

2 . notifyAll () Метод

Подобно wait () , метод notifyAll () используется в межпотоковом взаимодействии. Поток отвечает за выполнение обновления, и после выполнения некоторого обновления он отвечает за вызов метода notifyAll (), тогда ожидающий поток получит это уведомление и продолжит выполнение с обновленными элементами. notifyAll () также присутствует в классе java.lang .Object. Чтобы вызвать метод notifyAll () для любого объекта, они должны быть владельцем этого объекта, т. Е. Поток должен находиться внутри синхронизированной области. Следовательно, мы можем вызвать метод notifyAll () только из синхронизированной области, иначе мы получим исключение RuntimeException с сообщением IllegalMonitorStateExceptiom. Можно использовать метод notifyAll (), чтобы отправить уведомление всем ожидающим потокам определенного объекта, но даже если несколько потоков получают уведомление, но выполнение будет выполняться один за другим, потому что поток требует блокировки, и в данный момент доступна только одна блокировка. .

Синтаксис:

 public final native void notifyAll ()

Выполнение:

В приведенном ниже примере мы создаем класс myThread, обычно он называется так в программе, которая расширяет наш класс Thread, который сам по себе расширяет класс java.lang .Thread . Этот класс переопределяет метод run (), доступный в классе Thread, поток начинает свой жизненный цикл внутри метода run (). В классе драйвера ThreadN мы создаем объект и вызываем метод start, чтобы начать выполнение потока, и вызываем метод run () в классе ThreadN, мы синхронизировали поток t1 и поместили его в состояние ожидания. Внутри класса myThread мы синхронизируем метод выполнения и после вычисления суммы используем метод notifyAll (), чтобы уведомить ожидающий поток.

Пример

Ява

// Java Program to illustrate difference between
// wait() and notifyAll() method
// Importing java classes
// Input output classes
import java.io.*;
import java.lang.*;
// All utility classes from
// java.util package
import java.util.*;
// Creating a thread in our myThread class
// by extending the Thread class
// Class 1
// Helper class
class myThread extends Thread {
// Declaring sum variable and
// initializing with zero
// as the current final sum
// as it is before iteration
int sum = 0 ;
// Method in helper class
// Declaring run method
public void run()
{
// Synchronizing this method
synchronized ( this )
{
// Calculating the sum
// Display mwssage
System.out.println(
"child thread start calculation" );
// Iterating to calculate the sum
for ( int i = 0 ; i <= 100 ; i++)
// Updating the current sum where
// last updated sum is final sum
sum += i;
// Display mwssage
System.out.println(
"child thread trying to give notification" );
// This keyword refers to current object itself
// Notifing the current waiting thread
// using notifyAll() method
this .notifyAll();
}
}
}
// Class 2
// Main class
class ThreadN {
// Main driver method
public static void main(String[] args)
throws InterruptedException
{
// Creating a thread object
// in the main() method of
// our helper class above
myThread t1 = new myThread();
// Starting the above thread created
// using the start() method
t1.start();
// Synchronizing the thread
synchronized (t1)
{
// Display message
System.out.println(
"main thread trying to call wait method" );
// Putting the thread in the waiting state
// using the wait() method
t1.wait();
// Display message
System.out.println( "main thread get notify" );
// Print and display the sum
System.out.println(t1.sum);
}
}
}
Выход
 основной поток пытается вызвать метод ожидания
расчет запуска дочернего потока
дочерний поток пытается отправить уведомление
основной поток получить уведомление
5050

Now if the same program is run on terminal/CMD for custom user defined input then the hard coded input is shown below

Conclusion from the above program verifies the key differences between wait() and notifyAll() methods as follows: 

  1. ждать() используется для перевода потока в состояние ожидания, в то время как метод notifyAll () пробуждает весь ожидающий поток определенного объекта.
  2. Если поток вызывает метод wait () для любого объекта, он немедленно снимает блокировку этого конкретного объекта, но если поток вызывает метод notifyAll () для любого объекта, он также снимает блокировку этого конкретного объекта, но не сразу.
  3. Метод wait () генерирует исключение InterruptedException, в то время как метод notifyAll () не генерирует никаких исключений InterruptedException.

Вниманию читателя! Не прекращайте учиться сейчас. Ознакомьтесь со всеми важными концепциями Java Foundation и коллекций с помощью курса "Основы Java и Java Collections" по доступной для студентов цене и будьте готовы к работе в отрасли. Чтобы завершить подготовку от изучения языка к DS Algo и многому другому, см. Полный курс подготовки к собеседованию .