내 프로그램에 Java에서 멀티 스레딩을 사용하고 있습니다. 스레드를 성공적으로 실행했지만 사용할 때 Thread.wait()
던지고 java.lang.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
데이터 구조를 사용하십시오 .
wait
, 절대 접근 할 수 없습니다 notify
. 그러나에 대한 API 문서 Object.wait
에서 "스레드가이 모니터의 소유권을 해제합니다". 따라서 wait
마치 마치 둘러싸는 synchronized
블록 외부에있는 것처럼 보입니다 (동일한 객체의 경우 같은 객체에 여러 synchronized
블록이 있을 수 있음 ).
나는이 스레드가 거의 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();
세 가지 문제가 있습니다.
다른 사람들이 말했듯 obj.wait()
이 현재 스레드가 기본 잠금 / 뮤텍스를 보유하고있는 경우에만 호출 할 수 있습니다 obj
. 현재 스레드가 잠금을 보유하지 않으면 현재보고있는 예외가 발생합니다.
thread.wait()
전화는 당신이 그것을 할 것으로 예상 것으로 보인다 무엇을하지 않습니다. 특히 지정된 스레드가 대기 thread.wait()
하지 않습니다 . 오히려 원인 현재 스레드가 다른 스레드를 호출 할 때까지 기다려야 thread.notify()
또는 thread.notifyAll()
.
Thread
원하지 않는 경우 인스턴스를 강제 로 일시 중지 시키는 안전한 방법은 실제로 없습니다 . (Java가 가장 가까운 Thread.suspend()
방법 은 더 이상 사용되지 않는 방법이지만 Javadoc에 설명 된대로 해당 방법은 본질적으로 안전하지 않습니다 .)
새로 시작 Thread
을 일시 중지하려면 가장 좋은 방법은 CountdownLatch
인스턴스 를 만들고 await()
래치 에서 스레드를 호출 하여 일시 중지하는 것입니다. 그러면 메인 스레드는 countDown()
래치를 호출 하여 일시 중지 된 스레드가 계속되도록합니다.
이전 포인트와 직교하여 Thread
객체를 잠금 / 뮤텍스로 사용 하면 문제가 발생할 수 있습니다. 예를 들어, javadoc Thread::join
은 다음 과 같이 말합니다.
이 구현은에 설정된 루프
this.wait
호출을 사용합니다this.isAlive
. 스레드가 종료되면this.notifyAll
메소드가 호출됩니다. 이 응용 프로그램을 사용하지 않는 것이 좋습니다wait
,notify
또는notifyAll
에Thread
인스턴스.
코드를 게시하지 않았으므로 우리는 어둠 속에서 일하고 있습니다. 예외의 세부 사항은 무엇입니까?
스레드 내부 또는 외부에서 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) { }
}
wait()
.
worker.wait()
회선 에 대해 이야기하고 있습니까? 그런 다음 잠금 장치가 아닌 작업자와 동기화해야합니다.
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
동기화되지 않은 객체를 기다리려고한다는 것은 불법입니다.
IllegalMonitorStateException
다른 class
/ 스레드 에서 /에서 스레드를 깨우려고 하는 동안 잠시 받았습니다 . 에서 java 8
당신에게 사용할 수있는 lock
새로운 동시성 API의 기능을 대신 의 synchronized
기능을.
이미 asynchronous
웹 소켓 트랜잭션을 위한 객체를에 저장 했습니다 WeakHashMap
. 필자의 경우 해결책은 회신을 위해 객체를 저장하는lock
ConcurrentHashMap
것이 었습니다 synchronous
. (not 아님 )에 유의 하십시오 .condition.await
.wait
멀티 스레딩을 처리하기 위해 a Executors.newCachedThreadPool()
를 사용하여 스레드 풀 을 만들었습니다 .
Java 7.0 이하 버전을 사용하는 사람들은 여기에서 사용한 코드를 참조 할 수 있으며 작동합니다.
public class WaitTest {
private final Lock lock = new ReentrantLock();
private final Condition condition = lock.newCondition();
public void waitHere(long waitTime) {
System.out.println("wait started...");
lock.lock();
try {
condition.await(waitTime, TimeUnit.SECONDS);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
lock.unlock();
System.out.println("wait ends here...");
}
public static void main(String[] args) {
//Your Code
new WaitTest().waitHere(10);
//Your Code
}
}