wait () 호출시 IllegalMonitorStateException 내 프로그램에

내 프로그램에 Java에서 멀티 스레딩을 사용하고 있습니다. 스레드를 성공적으로 실행했지만 사용할 때 Thread.wait()던지고 java.lang.IllegalMonitorStateException있습니다. 스레드가 알림을받을 때까지 기다리려면 어떻게해야합니까?



답변

당신이 일 synchronized하기 위해서는 블록에 있어야 Object.wait()합니다.

또한 구식 스레딩 패키지 대신 동시성 패키지를 확인하는 것이 좋습니다. 더 안전하고 작업하기 쉽습니다 .

행복한 코딩.

편집하다

Object.wait()객체 잠금을 유지하지 않고 액세스하려고 할 때 예외가 발생 한다는 것을 의미한다고 가정했습니다 .


답변

wait에 정의되어 Object있지만 아닙니다 Thread. 모니터 Thread가 약간 예측할 수 없습니다.

모든 Java 객체에는 모니터가 있지만 일반적으로 전용 잠금 장치를 사용하는 것이 좋습니다.

private final Object lock = new Object();

명명 된 클래스를 사용하면 적은 메모리 비용 (프로세스 당 약 2K)으로 진단을보다 쉽게 ​​읽을 수 있습니다.

private static final class Lock { }
private final Object lock = new Lock();

하기 위해 wait또는 notify/ notifyAll객체, 당신은 함께 잠금 유지 될 필요가 synchronized문을. 또한 while깨우기 상태를 확인하기 위해 루프 가 필요합니다 (이유를 설명하기 위해 스레딩에 대한 좋은 텍스트를 찾으십시오).

synchronized (lock) {
    while (!isWakeupNeeded()) {
        lock.wait();
    }
}

알리기 위해:

synchronized (lock) {
    makeWakeupNeeded();
    lock.notifyAll();
}

멀티 스레딩에 들어갈 때 Java 언어와 java.util.concurrent.locks잠금 (및 java.util.concurrent.atomic)을 모두 이해하는 것이 좋습니다. 그러나 가능하면 java.util.concurrent데이터 구조를 사용하십시오 .


답변

나는이 스레드가 거의 2 세라는 것을 알고 있지만 동일한 문제 로이 Q / A 세션에 왔기 때문에 여전히 이것을 닫아야합니다 …

이 illegalMonitorException 정의를 반복해서 읽으십시오.

IllegalMonitorException은 스레드가 객체의 모니터를 기다리려고 시도했거나 지정된 모니터를 소유하지 않고 객체의 모니터를 기다리는 다른 스레드에 알리려고 시도했음을 나타냅니다.

이 줄은 두 가지 상황 중 하나가 발생할 때 IllegalMonitorException이 계속 발생한다고 말합니다.

1> 지정된 모니터를 소유하지 않고 객체의 모니터를 기다립니다.

2> 지정된 모니터를 소유하지 않고 객체의 모니터를 기다리는 다른 스레드에 알립니다.

어떤 사람들은 대답을 얻었을 수도 있습니다 … 모두 그렇지 않은 사람은 2 명을 확인하십시오 …

동기화 (개체)

object.wait ()

물체 모두 가 동일한 에는 illegalMonitorException이 발생하지 않습니다.

이제 IllegalMonitorException 정의를 다시 읽으면 다시 잊어 버리지 않습니다.


답변

귀하의 의견을 바탕으로 다음과 같은 일을하는 것처럼 들립니다.

Thread thread = new Thread(new Runnable(){
    public void run() { // do stuff }});

thread.start();
...
thread.wait();

세 가지 문제가 있습니다.

  1. 다른 사람들이 말했듯 obj.wait()이 현재 스레드가 기본 잠금 / 뮤텍스를 보유하고있는 경우에만 호출 할 수 있습니다 obj. 현재 스레드가 잠금을 보유하지 않으면 현재보고있는 예외가 발생합니다.

  2. thread.wait()전화는 당신이 그것을 할 것으로 예상 것으로 보인다 무엇을하지 않습니다. 특히 지정된 스레드가 대기 thread.wait() 하지 않습니다 . 오히려 원인 현재 스레드가 다른 스레드를 호출 할 때까지 기다려야 thread.notify()또는 thread.notifyAll().

    Thread원하지 않는 경우 인스턴스를 강제 로 일시 중지 시키는 안전한 방법은 실제로 없습니다 . (Java가 가장 가까운 Thread.suspend()방법 은 더 이상 사용되지 않는 방법이지만 Javadoc에 설명 된대로 해당 방법은 본질적으로 안전하지 않습니다 .)

    새로 시작 Thread을 일시 중지하려면 가장 좋은 방법은 CountdownLatch인스턴스 를 만들고 await()래치 에서 스레드를 호출 하여 일시 중지하는 것입니다. 그러면 메인 스레드는 countDown()래치를 호출 하여 일시 중지 된 스레드가 계속되도록합니다.

  3. 이전 포인트와 직교하여 Thread객체를 잠금 / 뮤텍스로 사용 하면 문제가 발생할 수 있습니다. 예를 들어, javadoc Thread::join은 다음 과 같이 말합니다.

    이 구현은에 설정된 루프 this.wait호출을 사용합니다 this.isAlive. 스레드가 종료되면 this.notifyAll메소드가 호출됩니다. 이 응용 프로그램을 사용하지 않는 것이 좋습니다 wait, notify또는 notifyAllThread인스턴스.


답변

코드를 게시하지 않았으므로 우리는 어둠 속에서 일하고 있습니다. 예외의 세부 사항은 무엇입니까?

스레드 내부 또는 외부에서 Thread.wait ()을 호출하고 있습니까?

IllegalMonitorStateException에 대한 javadoc에 따르면 다음과 같습니다.

스레드가 지정된 모니터를 소유하지 않고 오브젝트의 모니터에서 대기하려고 시도했거나 오브젝트의 모니터에서 대기중인 다른 스레드에게 알리려고 시도했음을 표시합니다.

이 답변을 명확히하기 위해 스레드를 기다리는이 호출은 동기화 된 블록 내에서 호출되었지만 IllegalMonitorStateException도 발생합니다.


     private static final class Lock { }
     private final Object lock = new Lock();

    @Test
    public void testRun() {
        ThreadWorker worker = new ThreadWorker();
        System.out.println ("Starting worker");
        worker.start();
        System.out.println ("Worker started - telling it to wait");
        try {
            synchronized (lock) {
                worker.wait();
            }
        } catch (InterruptedException e1) {
            String msg = "InterruptedException: [" + e1.getLocalizedMessage() + "]";
            System.out.println (msg);
            e1.printStackTrace();
            System.out.flush();
        }
        System.out.println ("Worker done waiting, we're now waiting for it by joining");
        try {
            worker.join();
        } catch (InterruptedException ex) { }

    }

답변

IllegalMonitorStateException을 처리하려면 호출 스레드가 적절한 모니터를 소유 한 경우에만 wait, notify 및 notifyAll 메소드의 모든 호출이 발생하는지 확인해야합니다 . 가장 간단한 해결책은 이러한 호출을 동기화 된 블록 안에 넣는 것입니다. 동기화 된 명령문에서 호출 될 동기화 오브젝트는 모니터를 가져와야합니다.

다음은 모니터 개념을 이해하기위한 간단한 예입니다.

public class SimpleMonitorState {

    public static void main(String args[]) throws InterruptedException {

        SimpleMonitorState t = new SimpleMonitorState();
        SimpleRunnable m = new SimpleRunnable(t);
        Thread t1 = new Thread(m);
        t1.start();
        t.call();

    }

    public void call() throws InterruptedException {
        synchronized (this) {
            wait();
            System.out.println("Single by Threads ");
        }
    }

}

class SimpleRunnable implements Runnable {

    SimpleMonitorState t;

    SimpleRunnable(SimpleMonitorState t) {
        this.t = t;
    }

    @Override
    public void run() {

        try {
            // Sleep
            Thread.sleep(10000);
            synchronized (this.t) {
                this.t.notify();
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

답변

Thread.wait () 호출은 Thread.class 객체에서 동기화되는 코드 내에서 의미가 있습니다. 나는 그것이 당신이 의미하는 것이라고 생각하지 않습니다.
물어

스레드가 알림을받을 때까지 기다리려면 어떻게해야합니까?

현재 스레드 만 기다릴 수 있습니다. 다른 스레드는 동의하는 경우에만 부드럽게 기다리도록 요청할 수 있습니다.
어떤 조건을 기다리려면 잠금 객체가 필요합니다-Thread.class 객체는 매우 나쁜 선택입니다-단일 AFAIK이므로 동기화 (스레드 정적 메소드 제외)는 위험합니다.
Tom Hawtin은 동기화 및 대기에 대한 자세한 내용을 이미 설명했습니다.
java.lang.IllegalMonitorStateException동기화되지 않은 객체를 기다리려고한다는 것은 불법입니다.