java.lang.IllegalMonitorStateException:对象在wait()之前未被线程锁定?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/26590542/
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-11 02:53:01  来源:igfitidea点击:

java.lang.IllegalMonitorStateException: object not locked by thread before wait()?

javaandroidmultithreading

提问by Asthme

I am using progress dialog.i need to stop the thread when user close the progressdialog .unfortunately it giving exception pls help me..

我正在使用进度对话框。当用户关闭进度对话框时,我需要停止线程。不幸的是,它给出了异常,请帮助我..

In inner class

在内部类

class UpdateThread extends Thread{

    public  void run() {
        while (true){
            count=adapter.getCount();

            try {
               mHandler.post(  new Runnable() {
                    public  void run() {
                        Log.i(TAG,count+"count");
                        progressDialog.setMessage(count + "Device  found");
                    }
                });
                Thread.sleep(300);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

Oncreate

Oncreate

 updateThread=new UpdateThread();

 progressDialog= new ProgressDialog(GroupListActivity.this);
 synchronized (this) {
     updateThread.start();
 }

ondismissal

开除

   progressDialog.setOnDismissListener(new DialogInterface.OnDismissListener() {
        @Override
        public  void onDismiss(DialogInterface dialog) {
            try {
                synchronized (this) {
                    updateThread.wait(300);
                }

            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            Log.i(TAG,"Thread is stopped");
        }
    });

采纳答案by Solomon Slow

This is wrong:

这是错误的:

synchronized(foo) {
    foo.wait();
}

The problem is, what's going to wake this thread up? That is to say, how do you guaranteethat the other thread won't call foo.notify()beforethe first thread calls foo.wait()? That's important because the foo object will not remember that it was notified if the notify call happens first. If there's only one notify(), and if it happens before the wait(), then the wait() will never return.

问题是,什么会唤醒这个线程?也就是说,你怎么保证foo.notify()第一个线程调用之前其他线程不会调用foo.wait()?这很重要,因为如果首先发生通知调用,则 foo 对象将不会记住它已收到通知。如果只有一个notify(),并且它发生在wait() 之前,那么wait() 将永远不会返回。

Here's how wait and notify were meant to be used:

以下是 wait 和 notify 的用法:

private Queue<Product> q = ...;
private Object lock = new Object();

void produceSomething(...) {
    Product p = reallyProduceSomething();
    synchronized(lock) {
        q.add(p);
        lock.notify();
    }
}

void consumeSomething(...) {
    Product p = null;
    synchronized(lock) {
        while (q.peek() == null) {
            lock.wait();
        }
        p = q.remove();
    }
    reallyConsume(p);
}

The most important things to to note in this example are that there is an explicit test for the condition (i.e., q.peek() != null), and that nobody changes the condition without locking the lock.

在这个例子中需要注意的最重要的事情是有一个对条件的显式测试(即 q.peek() != null),并且没有人在不锁定锁的情况下改变条件。

If the consumer is called first, then it will find the queue empty, and it will wait. There is no moment when the producer can slip in, add a Product to the queue, and then notify the lock until the consumer is ready to receive that notification.

如果先调用消费者,则它会发现队列为空,然后等待。生产者没有时间可以插入,将产品添加到队列中,然后通知锁,直到消费者准备好接收该通知。

On the other hand, if the producer is called first, then the consumer is guaranteed not to call wait().

另一方面,如果首先调用生产者,则保证消费者不会调用wait()。

The loop in the consumer is important for two reasons: One is that, if there is more than one consumer thread, then it is possible for one consumer to receive a notification, but then another consumer sneaks in and steals the Product from the queue. The only reasonable thing for the fist consumer to do in that case is wait again for the next Product. The other reason that the loop is important is that the Javadoc says Object.wait() is allowed to return even when the object has not been notified. That is called a "spurious wakeup", and the correct way to handle it is to go back and wait again.

消费者中的循环很重要,原因有二:一是,如果有多个消费者线程,则有可能一个消费者收到通知,但随后另一个消费者潜入并从队列中窃取产品。在这种情况下,第一个消费者唯一合理的做法是再次等待下一个产品。循环很重要的另一个原因是 Javadoc 说即使没有通知对象,也允许 Object.wait() 返回。这就是所谓的“虚假唤醒”,正确的处理方法是返回并再次等待。

Also note: The lock is privateand the queue is private. That guarantees that no other compilation unit is going to interfere with the synchronization in this compilation unit.

另请注意:锁是private,队列是private。这保证了没有其他编译单元会干扰该编译单元中的同步。

And note: The lock is a different object from the queue itself. That guarantees that synchronization in this compilation unit will not interfere with whatever synchronization that the Queue implementation does (if any).

并注意:锁是与队列本身不同的对象。这保证了此编译单元中的同步不会干扰 Queue 实现所做的任何同步(如果有)。



NOTE: My example re-invents a wheel to prove a point. In real code, you would use the put() and take() methods of an ArrayBlockingQueue which would take care of all of the waiting and notifying for you.

注意:我的例子重新发明了一个轮子来证明一个观点。在实际代码中,您将使用 ArrayBlockingQueue 的 put() 和 take() 方法,它们将为您处理所有等待和通知。

回答by BarrySW19

You can only wait on an object if you already hold the lock on it, you could try:

如果您已经持有锁,您只能等待一个对象,您可以尝试:

synchronized (updateThread) {
    updateThread.wait(300);
}

... but I'm not really sure what you're trying to achieve with the locks.

...但我不太确定你想用锁来达到什么目的。

回答by Krease

It really looks like you're trying to use synchronizedand waitwhere you shouldn't be.

这真的看起来像你正在尝试使用synchronized,并wait在那里你不应该。

If you really want to wait for the thread to finish, you should be doing something like this

如果你真的想等待线程完成,你应该做这样的事情

In your UpdateThread:

在您的UpdateThread

class UpdateThread extends Thread{
    public AtomicBoolean stopped = new AtomicBoolean(false);
    public  void run() {
        while (!stopped.get()){
    .....

In your creation:

在您的创作中:

updateThread = new UpdateThread();
progressDialog = new ProgressDialog(GroupListActivity.this);
updateThread.start();    // no synchronization necessary

In your on dismiss:

在您解雇时:

progressDialog.setOnDismissListener(new DialogInterface.OnDismissListener() {
        @Override
        public  void onDismiss(DialogInterface dialog) {
            try {
                updateThread.stopped.set(true);
                updateThread.join(300);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            Log.i(TAG,"Thread is stopped");
        }
    });

Note, I added an exit condition to your thread so it will actually stop (as is, your thread will keep going). You'd probably want to make the exit condition private and add a setter for cleanliness. Also, I'm using jointo properly wait for your thread to complete.

请注意,我向您的线程添加了退出条件,因此它实际上会停止(原样,您的线程将继续运行)。您可能希望将退出条件设为私有并添加一个 setter 以保持清洁。另外,我正在使用join以正确等待您的线程完成。