웹사이트 검색

Java 스레드 대기, 알림 및 notifyAll 예제


Java의 Object 클래스에는 스레드가 리소스의 잠금 상태에 대해 통신할 수 있도록 하는 세 가지 최종 메서드가 포함되어 있습니다. 이러한 메서드는 wait(), notify() 및 notifyAll()입니다. 그래서 오늘은 자바 프로그램에서 wait, notify, notifyAll에 대해 알아보겠습니다.

Java의 대기, 알림 및 notifyAll

기다리다

개체 대기 메서드에는 세 가지 변형이 있습니다. 하나는 다른 스레드가 현재 스레드를 깨우기 위해 개체에 대한 notify 또는 notifyAll 메서드를 호출할 때까지 무기한 대기하는 것입니다. 다른 두 가지 변형은 현재 스레드가 깨어나기 전에 특정 시간 동안 대기하도록 합니다.

알리다

notify 메소드는 객체를 기다리고 있는 하나의 스레드만 깨우고 해당 스레드는 실행을 시작합니다. 따라서 개체를 기다리는 여러 스레드가 있는 경우 이 메서드는 그 중 하나만 깨울 것입니다. 깨울 스레드의 선택은 스레드 관리의 OS 구현에 따라 다릅니다.

모두 알림

notifyAll 메소드는 객체를 기다리고 있는 모든 쓰레드를 깨운다. 어떤 쓰레드가 먼저 처리될지는 OS 구현에 달려 있다. 이러한 메서드는 소비자 스레드가 대기열의 개체를 기다리고 생산자 스레드가 개체를 대기열에 넣고 대기 중인 스레드에 알리는 생산자 소비자 문제를 구현하는 데 사용할 수 있습니다. 동일한 개체에서 여러 스레드가 작동하고 wait, notify 및 notifyAll 메서드를 사용하는 예를 살펴보겠습니다.

메시지

스레드가 작동하고 대기 및 알림 메소드를 호출하는 Java Bean 클래스.

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 스레드는 동기화된 블록을 사용하여 메시지 개체에 대한 모니터를 소유하고 있습니다.

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());
        }
    }

}

알리미

Message 개체를 처리한 다음 알림 메서드를 호출하여 Message 개체를 기다리는 스레드를 깨우는 클래스입니다. 동기화된 블록은 메시지 개체의 모니터를 소유하는 데 사용됩니다.

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");
    }

}

위의 프로그램을 호출하면 아래와 같은 출력이 표시되지만 메시지 개체를 기다리는 두 개의 스레드가 있고 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 스레드와 프로그램을 모두 깨우고 실행 후 프로그램을 완료하고 종료합니다. 이것이 java의 wait, notify 및 notifyAll에 대한 전부입니다.