synchronized, wait, notify

PeteProgram

Mitglied
Hallo

Habe eine großes Problem innerhalb meiner Anwendung mit den JEditorPane und der setPage() Methode in Verbindung mit dem UndoableEditListener:

Code:
...
//Der PropertyChangeListener, der überliefern soll, wenn ein Document via setPage(URL komplett geladen ist)
editorPane.addPropertyChangeListener(new DocumentLoadListener(this));
...
 
//Alter Listener weg
editorPane.getDocument().removeUndoableEditListener(undoHandler);
   try {
//Neues Document über URL laden --> asynchroner Thread
      editorPane.setPage(vm.getPage());
   } catch (IOException e) {
   ...
}
 
//Da das laden asynchron läuft, muss jetzt dass editorpane gestoppt werden
synchronized(this) {
   try {
      this.wait();
   } catch (InterruptedException e) {
      ...
   }
}
 
editorPane.getDocument().addUndoableEditListener(undoHandler);
 
...
 
//Der Listener
class DocumentLoadListener implements PropertyChangeListener {
   Object o;
   DocumentLoadListener(Object o) {
      super();
      this.o = o;
   }
 
   public void propertyChange(PropertyChangeEvent evt) {
      if (evt.getPropertyName().equals("page")) {
         System.out.println("notify")
         synchronized (o) {
             o.notify();
         }
       }
    }

Es kommt keine Fehlermeldung, die Seite wird nicht geladen. Wenn ich wait(1000) code, erscheint die Seite und über println kommt notify... Ich will aber keine feste Zeitspanne vorgeben, weill ich nie weiß wie lange das Laden dauern wird.

Hat jemand eine Idee, wer den Monitor braucht, bzw. was ich hier tun kann?
 
Zuletzt bearbeitet:
Hallo!

Weshalb arbeitest du da denn mit Low-Level Synchronisierung?
Lade einfach das Dokument asynchron ueber einen WorkerThread (SwingWorker Pattern, SwingUtilities.invokeLater(...)) und ruf einfach fuer die Dauer des Dokumentladevorgangs setEditable(false) am EditorPane auf. Innerhalb der Dokumentlade Methode kannst du dann als letzte Aktion den Editor wieder aktivieren.

Gruss Tom
 
Hallo, danke für Deine Antwort.

SwingUtilities.invokeLater(...)) teilt mir leider mit dass es nicht geht:
Cannot call invokeAndWait from the event dispatcher thread.

Ich habe ein bißchen gegoogelt, aber nix gefunden, dass mir dazu weiterhilft; außer:

...
Die Methode wird über einen ActionListener aufgerufen
event dispatch thread = thread that calls on listeners;
...


Die SwingWorker Klasse habe ich mir auch angeschaut aber:

Grundsätzlich bleibt das Problem doch dasselbe, wenn ich einen neuen Thread starte und dieser JEditorPane.setPage(URL) durchführt, dann wird die JVM noch einen asynchronen Thread zum Pageladen starten und mein eigener Thread teilt mir wieder viel zu zeitig mit, dass er schon fertig ist.

Dass zumindest, lese ich aus dem Sourcecode vom JEditorPane raus.

Um noch einmal auf mein wait(), notify -Problem zurückzukommen, kann mir jemand sagen, was da falsch läuft?
 
In Deinem Beispiel wartest Du "für immer", das erklärt auch, warum es bei wait(1000) funktioniert, denn dieser Aufruf sagt: "Warten! Wenn nichts innerhalb der nächsten 1000ms passiert, dann gehe weiter...".

Du mußt mit this.notify() das Warten rechtzeitig wieder freigeben! So wie ich Deinen Code verstehe, wird die Freigabe nur drch Ablauf der Zeit (wait(1000)) realisiert. Irgendwann rufst Du dann noch notify() auf, das an dieser Stelle allerdings keinen Effekt mehr hat.

Da Dein Code unvollständig abgebildet ist, fällt es mir schwer, die richtige Code-Zeile auszumachen, an der der notify()-Aufruf sinnvoller wäre.
Wenn ich mit wait()- und notify() arbeite, nutze ich dafür stets ein stinknormales Objekt, das ich nur zum Sperren und Freigeben nutze. Damit stelle ich sicher, immer vom gleichen Objekt "zu reden". Du übergibst "this" (Dein Sperrobjekt) an den Listener, der das als Sperr-Objekt verwendet. Das ist etwas unleserlicher, aber korrekt.
 
Hallo,
ich wiil gerne wissen wie hast Du das Problem gelöst.
Ich habe den gleichen Fehler, den Du schon Mal gehabt hast, nämlich:

Cannot call invokeAndWait from the event dispatcher thread

und zwar an der Stelle:

SwingUtilities.invokeAndWait(new Runnable(){
// do some things
}

Danke,
 
Zurück