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

时间:2014-10-27 15:04:34

标签: java android multithreading

我正在使用进度dialog.i需要在用户关闭progressdialog时停止该线程。不幸的是,它给了例外请帮助我..

在内部课堂

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

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

3 个答案:

答案 0 :(得分:56)

这是错误的:

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

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

以下是如何使用等待和通知:

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

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

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

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

消费者中的循环很重要有两个原因:一个是,如果有一个以上的消费者线程,那么一个消费者可能会收到一个通知,但是另一个消费者会偷偷摸摸并窃取产品队列。在这种情况下,第一个消费者唯一合理的做法是再次等待下一个产品。循环很重要的另一个原因是Javadoc说即使没有通知对象,也允许返回Object.wait()。这被称为&#34;虚假的唤醒&#34;,处理它的正确方法是返回并再次等待。

另请注意:锁定为private,队列为private。这保证了其他编译​​单元不会干扰此编译单元中的同步。

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


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

答案 1 :(得分:8)

如果您已经锁定了某个对象,则只能等待它,您可以尝试:

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

......但我不确定你想用锁来实现什么。

答案 2 :(得分:0)

看起来你似乎正在尝试使用synchronizedwait,而不应该这样做。

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

UpdateThread

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

在你的创作中:

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

在你的解雇中:

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

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