2014-10-27 83 views
30

我使用进度dialog.i需要停止线程,当用户关闭progressdialog。不幸的是它给人的异常请帮助我..java.lang.IllegalMonitorStateException:对象在wait()之前未被线程锁定?

在内部类

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

你究竟想用锁来达到什么目的? – Krease 2014-10-27 17:14:53

+0

@Chris它的异常。因此我必须锁定 – Asthme 2014-10-27 17:20:12

+0

我明白,如果您要调用'wait',则必须使用synchronized,但是我没有得到(a)为什么要同步调用updateThread。开始“,或(b)为什么你使用'wait'开始(因为你没有使用'notify'或'notifyAll')。我怀疑你正在同步并在不应该使用“wait”的地方使用。 – Krease 2014-10-27 17:25:45

回答

42

这是错误的:

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()被允许返回,即使对象没有被通知。这被称为“虚假唤醒”,正确的处理方法是返回并再次等待。

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

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


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

+0

.Awesome explanation.i将尝试整合并让你知道 – Asthme 2014-10-27 17:32:06

+0

wait()会在阻塞其线程之前释放对象监视器,所以它不会阻塞调用notify的其他线程。 (来自http://stackoverflow.com/questions/7126550/java-wait-and-notify-illegalmonitorstateexception#comment43938703_7126587) – Mygod 2015-12-03 18:04:13

+0

@Mygod,是的。调用'o.wait()'释放调用线程对'o'的锁,然后等待通知,然后在返回之前重新获得锁。 – 2015-12-03 18:08:12

6

你可以只wa它,如果你已经持有它的锁定的对象上,你可以尝试:

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

...但我真的不知道你想实现与锁什么。

0

它看起来像你试图使用​​和wait你不应该。

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

在你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正确等待您的线程完成。

相关问题