자바의 Object 클래스에는 스레드가 리소스의 락 상태에 대해 통신할 수 있게 해주는 세 가지 최종 메서드가 포함되어 있습니다. 이 메서드들은 wait(), notify(), notifyAll()입니다. 그래서 오늘은 자바 프로그램에서 wait, notify 및 notifyAll을 살펴보겠습니다.
Java에서 wait, notify 및 notifyAll
이러한 메서드 중 현재 스레드가 객체 모니터를 가져야만 합니다. 그렇지 않으면 java.lang.IllegalMonitorStateException 예외가 발생합니다.
wait
Object wait 메서드에는 세 가지 변형이 있습니다. 하나는 현재 스레드를 다른 스레드가 객체에서 notify 또는 notifyAll 메서드를 호출할 때까지 무기한 대기합니다. 다른 두 가지 변형은 현재 스레드를 깨우기 전에 특정 시간 동안 대기 상태로 둡니다.
notify
notify 메소드는 대기중인 객체에 대해 대기 중인 단 하나의 스레드만을 깨우고 그 스레드가 실행을 시작합니다. 따라서 여러 스레드가 객체를 기다리고 있는 경우, 이 메소드는 그 중 하나만을 깨웁니다. 깨울 스레드의 선택은 스레드 관리의 운영 체제 구현에 따라 달라집니다.
notifyAll
notifyAll 메소드는 객체에 대해 대기 중인 모든 스레드를 깨우며, 어떤 스레드가 먼저 처리될지는 운영 체제 구현에 따라 달라집니다. 이러한 메소드들은 생산자-소비자 문제를 구현하는 데 사용될 수 있습니다. 여기서 소비자 스레드는 큐에 있는 객체를 기다리고 있으며, 생산자 스레드는 큐에 객체를 넣고 대기 중인 스레드들에게 알립니다. 동일한 객체에 대해 여러 스레드가 작업하는 예제와 wait, notify, notifyAll 메소드를 사용하는 방법을 살펴보겠습니다.
Message
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;
}
}
Waiter
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
여러 스레드를 만들고 시작하는 테스트 클래스입니다.
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
Notifier 클래스에서 notify() 호출을 주석 처리하고 notifyAll() 호출을 주석 해제하면 다음과 같은 출력이 생성됩니다.
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에 관한 설명은 여기까지입니다.
Source:
https://www.digitalocean.com/community/tutorials/java-thread-wait-notify-and-notifyall-example