Computer >> 컴퓨터 >  >> 프로그래밍 >> Java

자바에서 락을 획득하지 않고 wait() 메서드를 호출할 수 있을까?

결론부터 말하면 아니요, 락(lock)을 획득하지 않은 상태에서는 wait() 메서드를 호출할 수 없습니다.

자바에서는 먼저 해당 객체의 락을 획득한 후에야 그 객체에 대해 wait() 메서드를 호출할 수 있습니다. 이는 타임아웃 시간을 지정하든 지정하지 않든 마찬가지입니다. 만약 락을 획득하지 않은 상태에서 wait() 메서드를 호출하려고 하면, 런타임에 java.lang.IllegalMonitorStateException 예외가 발생합니다.

예제 코드

public class ThreadStateTest extends Thread {
    public void run() {
        try {
            wait(1000);
        } catch(InterruptedException ie) {
            ie.printStackTrace();
        }
    }
    public static void main(String[] s) {
        ThreadStateTest test = new ThreadStateTest();
        test.start();
    }
}

위 예제에서는 락을 획득하지 않은 상태에서 wait() 메서드를 호출하고 있습니다. 따라서 프로그램을 실행하면 다음과 같이 IllegalMonitorStateException이 발생합니다.

실행 결과

Exception in thread "Thread-0" java.lang.IllegalMonitorStateException
at java.lang.Object.wait(Native Method)
at ThreadStateTest.run(ThreadStateTest.java:4)

문제 해결 방법

이 문제를 해결하려면 wait() 메서드를 호출하기 전에 반드시 해당 객체의 락을 획득해야 합니다. 가장 일반적인 방법은 synchronized 블록이나 synchronized 메서드를 사용하는 것입니다. 예를 들어 run() 메서드 내부에 synchronized(this) 블록을 추가하거나, run() 메서드 자체를 synchronized로 선언하면 됩니다.

public class ThreadStateTest extends Thread {
    public void run() {
        try {
            synchronized(this) { // 락을 획득한 후 wait() 호출
                wait(1000);
            }
        } catch(InterruptedException ie) {
            ie.printStackTrace();
        }
    }
    public static void main(String[] s) {
        ThreadStateTest test = new ThreadStateTest();
        test.start();
    }
}

정리하면, wait(), notify(), notifyAll() 같은 Object 클래스의 스레드 제어 메서드들은 모두 현재 스레드가 해당 객체의 모니터 락을 소유하고 있는 상태에서만 호출할 수 있다는 점을 기억해야 합니다. 그렇지 않으면 항상 IllegalMonitorStateException이 발생하게 됩니다.