Wait ()调用时的 IllegalMonitor 异常

我正在使用 Java 中的多线程为我的程序。 我已经成功地运行了线程,但是当我使用 Thread.wait()时,它抛出了 java.lang.IllegalMonitorStateException。 我如何让一个线程等待,直到它将被通知?

283802 次浏览

你需要在一个 synchronized块为了 Object.wait()的工作。

此外,我建议查看并发包,而不是旧的学校线程包。他们更安全,方式 更容易合作

剪辑

我假设您的意思是 Object.wait(),因为您的异常是当您试图获得访问而不持有对象锁定时发生的情况。

由于您还没有发布代码,我们有点摸不着头脑。异常的细节是什么?

您是从线程内部还是从线程外部调用 Thread.wait () ?

我问这个问题是因为根据 javadoc for IllegalMonitor 的 StateException,它是:

抛出以指示线程试图等待对象的监视器,或通知其他等待对象监视器的线程,而不拥有指定的监视器。

为了澄清这个答案,这个在线程上等待的调用也会抛出 IllegalMonitor 或 StateException,尽管这个调用是从一个同步块中调用的:


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是在 Object中定义的,而不是在 Thread中。 Thread上的监视器有点不可预测。

尽管所有 Java 对象都有监视器,但是通常最好有一个专用的锁:

private final Object lock = new Object();

通过使用命名类,您可以以较小的内存成本(大约每个进程2K)更容易地读取诊断信息:

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

为了使 waitnotify/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 ()调用在 Thread.class 对象上同步的代码中是有意义的。
你问吧

我如何让一个线程等待,直到它将被通知?

只能让当前线程等待。任何其他线程只能轻轻地要求等待,如果它同意。
如果你想等待一些条件,你需要一个锁对象-Thread.class 对象是一个非常糟糕的选择-它是一个单例 AFAIK,因此在它上面同步(除了 Thread 静态方法)是危险的。
同步和等待的细节已经由 Tom Hawtin 解释过了。 java.lang.IllegalMonitorStateException表示您正在尝试等待未同步的对象——这样做是非法的。

根据你的评论,听起来你正在做这样的事情:

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


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

有三个问题。

  1. 正如其他人所说,只有当前线程持有 obj的基本锁/互斥锁时,才能调用 obj.wait()。如果当前线程不持有该锁,则会得到所看到的异常。

  2. thread.wait()调用不会做您似乎期望它做的事情。具体来说,thread.wait() 没有会导致指定的线程等待。相反,它会导致 当前线程等待,直到其他线程调用 thread.notify()thread.notifyAll()

    实际上,如果 Thread实例不想暂停,就没有安全的方法来强制它暂停。(Java 与此最接近的方法是不推荐的 Thread.suspend()方法,但是正如 Javadoc 中所解释的那样,该方法本质上是不安全的。)

    如果希望暂停新启动的 Thread,最好的方法是创建一个 CountdownLatch实例,并让锁存器上的线程调用 await()使其自身暂停。然后,主线程将调用锁存器上的 countDown(),让暂停的线程继续运行。

  3. 与前面的要点正交,使用 Thread对象作为锁/互斥可能会导致问题。例如,Thread::join的 javadoc 说:

    这个实现使用了一个以 this.isAlive为条件的 this.wait调用循环。当线程终止时,将调用 this.notifyAll方法。建议应用程序不要在 Thread实例上使用 waitnotifynotifyAll

我知道这个帖子已经有2年的历史了,但仍然需要关闭它,因为我也带着同样的问题来到这个问答环节..。

请一遍又一遍地阅读这个定义..。

引发 IllegalMonitor 异常以指示某个线程试图等待对象的监视器,或通知其他正在等待对象监视器的线程,而不拥有指定的监视器。

这一行一次又一次地说,当两种情况中的一种发生时,就会出现 IllegalMonitor 异常... ..。

等待对象的监视器而不拥有指定的监视器。

2 > 通知正在等待对象监视器的其他线程,而不拥有指定的监视器。

有些人可能已经得到了答案... ... 谁都没有,那么请检查2个陈述... 。

同步的(对象)

Object.wait ()

如果两个 对象是相同的... 那么就不会出现非法的 Monitor 异常。

现在再次阅读 IllegalMonitor 异常定义,您将不会再次忘记它..。

不知道这是否会帮助其他人,但这是解决我的问题的关键部分,在用户“ Tom Hawtin-taclin”的回答上面:

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

事实上,“ lock”在 synized ()中作为参数传递,并且它也在“ lock”中使用

一旦我在那两个地方成功了,我就让它工作起来了

我在尝试从不同的 class/线程中唤醒一个线程时收到了一个 IllegalMonitorStateException。在 java 8中,可以使用 synchronized函数的 新的并发 API 的 lock特性 取而代之

我已经在一个 WeakHashMap中存储了 asynchronous websocket 事务的对象。在我的情况下,解决方案也是 在 ABC3中存储 lock对象synchronous答复。注意 the condition.await(不是 .wait)。

为了处理多线程,我使用了一个 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
}


}

为了处理 Illegalmonitor orStateException,必须验证所有对 wait、 tification 和 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();
}
}
}

对于在对象上调用 wait ()/tification () ,它需要位于 sync 块中。首先你必须锁定对象然后才能调用这些函数。

synchronized(obj)
{
obj.wait()
}

详细解释: Https://dzone.com/articles/multithreading-java-and-interviewspart-2

Wait ()、 notifyAll ()和 notifyAll ()方法只能在 同步上下文同步上下文中调用。

例如,在同步块中:

syncronized (obj) {
obj.wait();
}

或者,以同步方式:

syncronized static void myMethod() {
wait();
}