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

Posted

技术标签:

【中文标题】java.lang.IllegalMonitorStateException:在等待()之前对象没有被线程锁定?【英文标题】:java.lang.IllegalMonitorStateException: object not locked by thread before wait()? 【发布时间】:2014-12-22 19:22:52 【问题描述】:

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

在内部类中

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

创建

 updateThread=new UpdateThread();

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

解雇

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

【问题讨论】:

你到底想用锁实现什么? @Chris 它给出异常。所以我必须锁定 我知道如果你打电话给wait,你必须使用同步,但我不明白(a)为什么你在调用updateThread.start时也要同步,或者(b)为什么要使用wait 开头(因为您没有使用notifynotifyAll)。我怀疑您正在同步并使用 wait 不应该在的地方。 添加了一个答案,可以更改您的代码以完成您想要做的事情。 【参考方案1】:

看起来您确实在尝试在不应该使用的地方使用 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");
        
    );

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

【讨论】:

【参考方案2】:

这是错误的:

synchronized(foo) 
    foo.wait();

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

下面是 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);

在此示例中需要注意的最重要的事情是对条件进行了显式测试(即 q.peek() != null),并且没有人在不锁定锁的情况下更改条件。

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

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

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

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

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


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

【讨论】:

。很棒的解释。我会尝试整合并让你知道 wait() 会在阻塞其线程之前释放对象监视器,因此它不会阻塞其他调用 notify 的线程。 (来自***.com/questions/7126550/…) @Mygod,是的。对o.wait() 的调用会释放调用线程在o 上的锁,然后等待通知,然后在返回之前重新获取锁。 @jameslarge 我不知道,所以我认为这段代码行不通。 我会将“final”修饰符添加到私有对象锁【参考方案3】:

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

synchronized (updateThread) 
    updateThread.wait(300);

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

【讨论】:

以上是关于java.lang.IllegalMonitorStateException:在等待()之前对象没有被线程锁定?的主要内容,如果未能解决你的问题,请参考以下文章