Класс Object в Java содержит три финальных метода, которые позволяют потокам обмениваться информацией о состоянии блокировки ресурса. Этими методами являются wait(), notify() и notifyAll(). Поэтому сегодня мы рассмотрим использование wait, notify и notifyAll в программе на Java.
wait, notify и notifyAll в Java
Текущий поток, вызывающий эти методы для любого объекта, должен иметь монитор объекта, иначе будет сгенерировано исключение java.lang.IllegalMonitorStateException.
wait
У методов ожидания объекта есть три варианта, один из которых ожидает неопределенно, чтобы какой-либо другой поток вызвал метод notify или notifyAll для разблокировки текущего потока. Другие два варианта ожидают определенное время, прежде чем разблокировать текущий поток.
notify
notify-метод разбудит только один поток, ожидающий объект, и этот поток начнет выполнение. Таким образом, если существует несколько потоков, ожидающих объект, этот метод разбудит только один из них. Выбор потока, который будет разбужен, зависит от реализации ОС управления потоками.
notifyAll
Метод notifyAll разбудит все потоки, ожидающие объект, хотя порядок их обработки зависит от реализации ОС. Эти методы могут использоваться для решения проблемы производителя и потребителя, где потоки-потребители ожидают объекты в очереди, а потоки-производители помещают объект в очередь и уведомляют ожидающие потоки. Давайте рассмотрим пример, где несколько потоков работают с одним и тем же объектом, и мы используем методы wait, notify и notifyAll.
Сообщение
A java bean class on which threads will work and call wait and notify methods.
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;
}
}
Официант
A class that will wait for other threads to invoke notify methods to complete it’s processing. Notice that Waiter thread is owning monitor on Message object using synchronized block.
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());
//обработать сообщение сейчас
System.out.println(name+" processed: "+msg.getMsg());
}
}
}
Уведомитель
A class that will process on Message object and then invoke notify method to wake up threads waiting for Message object. Notice that synchronized block is used to own the monitor of Message object.
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();
}
}
}
WaitNotifyTest
Тестовый класс, который создаст несколько потоков Waiter и Notifier и запустит их.
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");
}
}
Когда мы вызовем вышеуказанную программу, мы увидим следующий вывод, но программа не завершится, потому что есть два потока, ожидающих объект Message, и метод 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() разбудит оба потока Waiter, программа завершится и завершится после выполнения. Вот и все для wait, notify и notifyAll в Java.
Source:
https://www.digitalocean.com/community/tutorials/java-thread-wait-notify-and-notifyall-example