Автор оригинала: Pankaj Kumar.
Класс объектов в java содержит три конечных метода, которые позволяют потокам сообщать о состоянии блокировки ресурса. Этими методами являются wait() , notify() и notifyAll() . Поэтому сегодня мы рассмотрим ожидание, уведомление и оповещение всех в программе java.
ждите, уведомляйте и уведомляйте всех на Java
Текущий поток, который вызывает эти методы для любого объекта, должен иметь объект monitor иначе он выдает java.lang.Исключение IllegalMonitorStateException исключение.
ждать
Методы ожидания объекта имеют три варианта, один из которых бесконечно ожидает, пока любой другой поток вызовет метод notify или notifyAll для объекта, чтобы разбудить текущий поток. Два других варианта заставляют текущий поток ждать определенное время, прежде чем он проснется.
уведомлять
метод notify пробуждает только один поток, ожидающий объект, и этот поток начинает выполнение. Поэтому, если объект ожидает несколько потоков, этот метод разбудит только один из них. Выбор потока для пробуждения зависит от реализации управления потоками в операционной системе.
уведомИть всех
Метод notifyAll пробуждает все потоки, ожидающие объекта, хотя то, какой из них будет обработан первым, зависит от реализации ОС.
Эти методы могут быть использованы для реализации проблемы производителя-потребителя, когда потоки-потребители ожидают объекты в очереди, а потоки-производители помещают объект в очередь и уведомляют ожидающие потоки.
Давайте рассмотрим пример, когда несколько потоков работают над одним и тем же объектом, и мы используем методы wait, notify и notifyAll.
Сообщение
Класс java-компонента, над которым будут работать потоки и вызывать методы ожидания и уведомления.
package com.journaldev.concurrency; public class Message { private String msg; public Message(String str){ this.msg=str; } public String getMsg() { return msg; } public void setMsg(String str) { this.msg=str; } }
Официант
Класс, который будет ждать, пока другие потоки вызовут методы уведомления для завершения обработки. Обратите внимание, что поток официанта владеет монитором объекта сообщения с помощью синхронизированного блока.
package com.journaldev.concurrency; public class Waiter implements Runnable{ private Message msg; public Waiter(Message m){ this.msg=m; } @Override public void run() { String name = Thread.currentThread().getName(); synchronized (msg) { try{ System.out.println(name+" waiting to get notified at time:"+System.currentTimeMillis()); msg.wait(); }catch(InterruptedException e){ e.printStackTrace(); } System.out.println(name+" waiter thread got notified at time:"+System.currentTimeMillis()); //process the message now System.out.println(name+" processed: "+msg.getMsg()); } } }
Уведомитель
Класс, который будет обрабатывать объект сообщения, а затем вызывать метод notify, чтобы разбудить потоки, ожидающие объект сообщения. Обратите внимание, что синхронизированный блок используется для владения монитором объекта сообщения.
package com.journaldev.concurrency; public class Notifier implements Runnable { private Message msg; public Notifier(Message msg) { this.msg = msg; } @Override public void run() { String name = Thread.currentThread().getName(); System.out.println(name+" started"); try { Thread.sleep(1000); synchronized (msg) { msg.setMsg(name+" Notifier work done"); msg.notify(); // msg.notifyAll(); } } catch (InterruptedException e) { e.printStackTrace(); } } }
Подождите, Чтобы Уведомить Тест
Тестовый класс, который создаст несколько потоков Официанта и Уведомителя и запустит их.
package com.journaldev.concurrency; public class WaitNotifyTest { public static void main(String[] args) { Message msg = new Message("process it"); Waiter waiter = new Waiter(msg); new Thread(waiter,"waiter").start(); Waiter waiter1 = new Waiter(msg); new Thread(waiter1, "waiter1").start(); Notifier notifier = new Notifier(msg); new Thread(notifier, "notifier").start(); System.out.println("All the threads are started"); } }
Когда мы вызовем вышеприведенную программу, мы увидим вывод ниже, но программа не будет завершена, потому что есть два потока, ожидающих объекта сообщения, и метод notify() разбудил только один из них, другой поток все еще ждет уведомления.
waiter waiting to get notified at time:1356318734009 waiter1 waiting to get notified at time:1356318734010 All the threads are started notifier started waiter waiter thread got notified at time:1356318735011 waiter processed: notifier Notifier work done
Если мы прокомментируем вызов notify() и раскомментируем вызов notifyAll() в классе Notifier, ниже будет результат.
waiter waiting to get notified at time:1356318917118 waiter1 waiting to get notified at time:1356318917118 All the threads are started notifier started waiter1 waiter thread got notified at time:1356318918120 waiter1 processed: notifier Notifier work done waiter waiter thread got notified at time:1356318918120 waiter processed: notifier Notifier work done
Поскольку метод notifyAll() пробуждает как потоки официантов, так и программу, она завершается и завершается после выполнения. Это все для ожидания, уведомления и уведомления всех на java.