2014-10-27 4 views
30

ich Fortschritte bin mit dialog.i den Thread beenden müssen, wenn der Benutzer die progressdialog schließen .unfortunately es Ausnahme geben pls mir helfen ..java.lang.IllegalMonitorStateException: Objekt nicht vor dem Warten durch den Thread gesperrt()?

In inneren Klasse

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

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

Was genau versuchen Sie mit den Schlössern zu erreichen? – Krease

+0

@Chris gibt exception.so ich muss sperren – Asthme

+0

Ich verstehe, dass Sie synchronisiert verwenden müssen, wenn Sie 'wait' aufrufen, aber ich verstehe nicht (a), warum Sie auch beim Aufruf von' updateThread synchronisieren. start ', oder (b) warum Sie' wait' verwenden, um damit zu beginnen (da Sie nicht 'notify' oder' notifyAll' verwenden). Ich vermute, du synchronisierst und verwendest 'wait', wo du nicht sein solltest. – Krease

Antwort

42

Das ist falsch:

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

Das Problem ist, was dieses Thema zu wecken ist los? Das heißt, wie garantieren Sie , dass der andere Thread nicht foo.notify()vor der erste Thread ruft foo.wait() aufrufen wird? Das ist wichtig, weil das foo-Objekt sich nicht daran erinnert, dass es benachrichtigt wurde, wenn der Benachrichtigungsaufruf zuerst stattfindet. Wenn es nur eine notify() gibt, und wenn dies vor der wait() geschieht, wird wait() niemals zurückkehren.

Hier ist, wie warten und notify gemeint waren verwendet werden:

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

Die wichtigsten Dinge, die in diesem Beispiel zu beachten sind, dass es ein expliziter Test für den Zustand (dh q.peek() ! = null), und niemand ändert die Bedingung, ohne die Sperre zu sperren.

Wenn der Benutzer zuerst angerufen wird, wird die Warteschlange leer und es wird warten. Es gibt keinen Moment, an dem der Produzent hineinschlüpfen, ein Produkt zur Warteschlange hinzufügen und dann die Sperre mitteilen kann, bis der Verbraucher bereit ist, diese Benachrichtigung zu erhalten.

Auf der anderen Seite, wenn der Produzent zuerst angerufen wird, dann ist der Verbraucher garantiert nicht zu warten(). Die Schleife im Consumer ist aus zwei Gründen wichtig: Erstens, wenn es mehr als einen Consumer-Thread gibt, dann ist es möglich, dass ein Konsument eine Benachrichtigung erhält, aber dann schleicht sich ein anderer Konsument ein und stiehlt das Produkt aus der Warteschlange. Das einzig Vernünftige, was der erste Verbraucher in diesem Fall tun kann, ist wieder auf das nächste Produkt zu warten. Der andere Grund, warum die Schleife wichtig ist, ist, dass das Javadoc sagt, dass Object.wait() zurückgeben darf, selbst wenn das Objekt nicht benachrichtigt wurde. Das nennt man ein "unechtes Wakeup", und die richtige Art, damit umzugehen, ist es, zurück zu gehen und wieder zu warten.

Beachten Sie auch: Die Sperre ist private und die Warteschlange ist private. Dies garantiert, dass keine andere Übersetzungseinheit die Synchronisation in dieser Übersetzungseinheit stören wird.

Und Hinweis: Die Sperre ist ein anderes Objekt als die Warteschlange selbst. Dies garantiert, dass die Synchronisation in dieser Kompilierungseinheit nicht mit der Synchronisation kollidiert, die die Queue-Implementierung (falls vorhanden) ausführt.


HINWEIS: Mein Beispiel erfindet ein Rad neu, um einen Punkt zu beweisen. In realem Code würden Sie die put() - und take() - Methoden einer ArrayBlockingQueue verwenden, die sich um das Warten und Benachrichtigen für Sie kümmert.

+0

.Awesome Erklärung.I wird versuchen, zu integrieren und lassen Sie wissen – Asthme

+0

wait() würde Objekt Monitor vor dem Blockieren seines Threads freigeben, so würde es andere Threads nicht blockieren, die notify aufrufen. (von http://stackoverflow.com/questions/7126550/java-wait-and-notify-illegalmonitorstateexception#comment43938703_7126587) – Mygod

+0

@Mygod, Ja. Ein Aufruf von "o.wait()" gibt die Sperre des aufrufenden Threads für "o" frei, wartet dann auf eine Benachrichtigung und nimmt dann die Sperre erneut an, bevor sie zurückkehrt. –

6

Sie können nur wa es auf ein Objekt, wenn Sie bereits die Sperre für sie halten, könnten Sie versuchen:

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

... aber ich bin nicht wirklich sicher, was Sie mit den Schleusen zu erreichen versuchen.

0

Es sieht wirklich so aus, als ob Sie versuchen, synchronized und wait zu verwenden, wo Sie nicht sein sollten.

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

In Ihrer Kreation:

Wenn Sie wirklich für den Thread zu beenden warten wollen, sollten Sie so etwas wie dieses

In Ihrem UpdateThread tun

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

In Ihre Antwort:

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

Hinweis: Ich habe Ihrem Thread eine Exit-Bedingung hinzugefügt, so dass diese tatsächlich beendet wird (Ihr Thread wird weiterlaufen). Sie möchten wahrscheinlich die Ausgangsbedingung als privat definieren und einen Setter für die Sauberkeit hinzufügen. Außerdem verwende ich join, um ordnungsgemäß auf den Abschluss Ihres Threads zu warten.

Verwandte Themen