Java wait() 调用上的 IllegalMonitorStateException

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1537116/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-12 13:57:06  来源:igfitidea点击:

IllegalMonitorStateException on wait() call

javamultithreadingwait

提问by prakash.panjwani

I am using multi-threading in java for my program. I have run thread successfully but when I am using Thread.wait(), it is throwing java.lang.IllegalMonitorStateException. How can I make a thread wait until it will be notified?

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

采纳答案by reccles

You need to be in a synchronizedblock in order for Object.wait()to work.

您需要在一个synchronized街区中才能Object.wait()工作。

Also, I recommend looking at the concurrency packages instead of the old school threading packages. They are safer and way easier to work with.

此外,我建议查看并发包而不是旧式线程包。它们更安全,更易于使用

Happy coding.

快乐编码。

EDIT

编辑

I assumed you meant Object.wait()as your exception is what happens when you try to gain access without holding the objects lock.

我假设您的意思Object.wait()是当您尝试在不持有对象锁的情况下获得访问权限时会发生什么异常。

回答by CPerkins

Since you haven't posted code, we're kind of working in the dark. What are the details of the exception?

因为你还没有发布代码,我们有点在黑暗中工作。例外的细节是什么?

Are you calling Thread.wait() from within the thread, or outside it?

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

I ask this because according to the javadoc for IllegalMonitorStateException, it is:

我问这个是因为根据 IllegalMonitorStateException 的 javadoc,它是:

Thrown to indicate that a thread has attempted to wait on an object's monitor or to notify other threads waiting on an object's monitor without owning the specified monitor.
抛出以指示线程已尝试在对象监视器上等待或通知其他线程在不拥有指定监视器的情况下在对象监视器上等待。

To clarify this answer, this call to wait on a thread also throws IllegalMonitorStateException, despite being called from within a synchronized block:

为了澄清这个答案,这个等待线程的调用也会抛出 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) { }

    }

回答by Tom Hawtin - tackline

waitis defined in Object, and not it Thread. The monitor on Threadis a little unpredictable.

wait在 中定义Object,而不是在 中定义Thread。打开的显示器Thread有点不可预测。

Although all Java objects have monitors, it is generally better to have a dedicated lock:

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

private final Object lock = new Object();

You can get slightly easier to read diagnostics, at a small memory cost (about 2K per process) by using a named class:

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

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

In order to waitor notify/notifyAllan object, you need to be holding the lock with the synchronizedstatement. Also, you will need a whileloop to check for the wakeup condition (find a good text on threading to explain why).

为了waitnotify/notifyAll一个对象,您需要使用synchronized语句持有锁。此外,您将需要一个while循环来检查唤醒条件(找到有关线程的好文本来解释原因)。

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

To notify:

通知:

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

It is well worth getting to understand both Java language and java.util.concurrent.lockslocks (and java.util.concurrent.atomic) when getting into multithreading. But use java.util.concurrentdata structures whenever you can.

在进入多线程时,了解 Java 语言和java.util.concurrent.locks锁(和java.util.concurrent.atomic)是非常值得的。但是请java.util.concurrent尽可能使用数据结构。

回答by Tadeusz Kopec

Thread.wait() call make sense inside a code that synchronizes on Thread.class object. I don't think it's what you meant.
You ask

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

How can I make a thread wait until it will be notified?

如何让线程等待直到收到通知?

You can make only your current thread wait. Any other thread can be only gently asked to wait, if it agree.
If you want to wait for some condition, you need a lock object - Thread.class object is a very bad choice - it is a singleton AFAIK so synchronizing on it (except for Thread static methods) is dangerous.
Details for synchronization and waiting are already explained by Tom Hawtin. java.lang.IllegalMonitorStateExceptionmeans you are trying to wait on object on which you are not synchronized - it's illegal to do so.

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

回答by Stephen C

Based on your comments it sounds like you are doing something like this:

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

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

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

There are three problems.

存在三个问题。

  1. As others have said, obj.wait()can only be called if the current thread holds the primitive lock / mutex for obj. If the current thread does not hold the lock, you get the exception you are seeing.

  2. The thread.wait()call does not do what you seem to be expecting it to do. Specifically, thread.wait()does notcause the nominated thread to wait. Rather it causes the current threadto wait until some other thread calls thread.notify()or thread.notifyAll().

    There is actually no safe way to force a Threadinstance to pause if it doesn't want to. (The nearest that Java has to this is the deprecated Thread.suspend()method, but that method is inherently unsafe, as is explained in the Javadoc.)

    If you want the newly started Threadto pause, the best way to do it is to create a CountdownLatchinstance and have the thread call await()on the latch to pause itself. The main thread would then call countDown()on the latch to let the paused thread continue.

  3. Orthogonal to the previous points, using a Threadobject as a lock / mutex may cause problems. For example, the javadoc for Thread::joinsays:

    This implementation uses a loop of this.waitcalls conditioned on this.isAlive. As a thread terminates the this.notifyAllmethod is invoked. It is recommended that applications not use wait, notify, or notifyAllon Threadinstances.

  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 forThread::join说:

    此实现使用以 为this.wait条件的调用循环this.isAlive。当线程终止时,this.notifyAll调用该方法。建议应用程序无法使用waitnotifynotifyAllThread实例。

回答by Mina

I know this thread is almost 2 years old but still need to close this since I also came to this Q/A session with same issue...

我知道这个线程已经快 2 岁了,但仍然需要关闭它,因为我也带着同样的问题来到了这个问答环节......

Please read this definition of illegalMonitorException again and again...

请一遍又一遍地阅读这个非法监视器异常的定义......

IllegalMonitorException is thrown to indicate that a thread has attempted to wait on an object's monitor or to notify other threads waiting on an object's monitor without owning the specified monitor.

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

This line again and again says, IllegalMonitorException comes when one of the 2 situation occurs....

这一行一遍又一遍地说,IllegalMonitorException 出现在两种情况之一发生时......

1> wait on an object's monitor without owning the specified monitor.

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

2> notify other threads waiting on an object's monitor without owning the specified monitor.

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

Some might have got their answers... who all doesn't, then please check 2 statements....

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

synchronized (object)

同步(对象)

object.wait()

对象.wait()

If both objectare same... then no illegalMonitorException can come.

如果两个对象相同……那么就不会出现非法监视器异常。

Now again read the IllegalMonitorException definition and you wont forget it again...

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

回答by jp093121

Not sure if this will help somebody else out or not but this was the key part to fix my problem in user "Tom Hawtin - tacklin"'s answer above:

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

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

Just the fact that the "lock" is passed as an argument in synchronized() and it is also used in "lock".notifyAll();

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

Once I made it in those 2 places I got it working

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

回答by Stuart Cardall

I received a IllegalMonitorStateExceptionwhile trying to wake up a thread in / from a different class/ thread. In java 8you can use the lockfeatures of the new Concurrency APIinsteadof synchronizedfunctions.

我收到了一段IllegalMonitorStateException时间试图从不同的class/ 线程唤醒/ 中的线程。在java 8你可以使用lock新的API并发功能代替synchronized功能。

I was already storing objects for asynchronouswebsocket transactions in a WeakHashMap. The solution in my case was to also store a lockobject in a ConcurrentHashMapfor synchronousreplies. Notethe condition.await(not .wait).

我已经将asynchronouswebsocket 事务的对象存储在WeakHashMap. 在我的情况的解决方案是也存储lock在一个对象ConcurrentHashMapsynchronous回复。需要注意condition.await(不.wait)。

To handle the multi threading I used a Executors.newCachedThreadPool()to create a thread pool.

为了处理多线程,我使用 aExecutors.newCachedThreadPool()创建了一个线程池

回答by mannedear

Those who are using Java 7.0 or below version can refer the code which I used here and it works.

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

}

回答by Rakesh Chaudhari

In order to deal with the IllegalMonitorStateException, you must verify that all invocations of the wait, notify and notifyAll methods are taking place only when the calling thread owns the appropriate monitor. The most simple solution is to enclose these calls inside synchronized blocks. The synchronization object that shall be invoked in the synchronized statement is the one whose monitor must be acquired.

为了处理 IllegalMonitorStateException,您必须验证 wait、notify 和 notifyAll 方法的所有调用是否仅在调用线程拥有适当的 monitor 时发生。最简单的解决方案是将这些调用包含在同步块中。在synchronized 语句中应该调用的同步对象是必须获取其监视器的对象。

Here is the simple example for to understand the concept of monitor

这是理解监视器概念的简单示例

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();
        }
    }
}