wait()调用时出现IllegalMonitorStateException

时间:2009-10-08 11:09:01

标签: java multithreading wait

我在java中为我的程序使用多线程。 我已成功运行线程,但当我使用Thread.wait()时,它正在抛出java.lang.IllegalMonitorStateException。 我怎样才能让线程等到它会被通知?

10 个答案:

答案 0 :(得分:162)

您需要位于synchronized区块才能使Object.wait()生效。

另外,我建议查看并发包而不是旧的学校线程包。他们更安全,方式easier to work with

快乐的编码。

修改

我认为您的意思是Object.wait(),因为您尝试在不保持对象锁定的情况下获取访问权限时会发生异常。

答案 1 :(得分:50)

waitObject中定义,而不是ThreadThread上的监视器有点不可预测。

虽然所有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数据结构。

答案 2 :(得分:23)

我知道这个帖子差不多已有2年了但是仍然需要关闭它,因为我也遇到了同样问题的问答环节......

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

抛出IllegalMonitorException以指示线程已尝试在对象的监视器上等待,或者在没有指定监视器的情况下通知在对象监视器上等待的其他线程。

这一行一次又一次地说,IllegalMonitorException出现在2种情况中的一种情况发生....

1>在没有指定监视器的情况下等待对象的监视器。

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

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

synchronized(对象)

<强>的Object.wait()

如果两个对象相同...则不会发生illegalMonitorException。

现在再次阅读IllegalMonitorException定义,你不会再忘记它了......

答案 3 :(得分:5)

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

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对象作为锁/互斥锁可能会导致问题。例如,Thread::join的javadoc表示:

      

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

答案 4 :(得分:1)

由于您尚未发布代码,我们在黑暗中工作。该例外的细节是什么?

您是从线程内部还是外部调用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) { }

    }

答案 5 :(得分:1)

为了处理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();
        }
    }
}

答案 6 :(得分:0)

Thread.wait()调用在Thread.class对象上同步的代码中有意义。我不认为这就是你的意思 你问

  

如何让线程等到通知之后呢?

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

答案 7 :(得分:0)

不确定这是否会帮助其他人,但这是解决用户问题的关键部分“Tom Hawtin - tacklin”的答案:

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

事实上,“lock”作为参数在synchronized()中传递,它也用于“lock”.notifyAll();

一旦我在这两个地方做到了,我就开始工作了

答案 8 :(得分:0)

我在尝试从不同的IllegalMonitorStateException /线程中唤醒线程时收到了class。在java 8中,您可以使用synchronized 代替 asynchronous个函数。

我已经在WeakHashMap中存储了synchronous websocket交易的对象。在我的案例中,解决方案也是lock features of the new Concurrency APIcondition.await个回复。 注意 .wait(不是Executors.newCachedThreadPool())。

为了处理多线程,我使用select Name,Dateadded from table where date(dateadded) = '2009-12-11' 创建了store a lock object in a ConcurrentHashMap

答案 9 :(得分:0)

使用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
    }

}