2010-08-23 22 views
40

Warum muss GUI-Aktualisierungscode in SwingUtilities.invokeLater() eingegeben werden?SwingUtilities.invokeLater() warum wird es benötigt?

Warum kann es nicht intern von Swing selbst erledigt werden? Warum muss der Aufrufer sich darum kümmern, wie Swing UI-Aktualisierungen durchführt?

+1

Eigentlich ist diese Methode genau für den Entwickler ** nicht ** um Thread Synchronisation zu kümmern, für Sie Swing einfach wissen, es ist an der Zeit zu aktualisieren, und die schwere Arbeit wird hinter Szenen durchgeführt. – OscarRyz

Antwort

35

Swing-Objekte are not thread safe. SwingUtilities.invokeLater() ermöglicht es, eine Aufgabe zu einem späteren Zeitpunkt auszuführen, wie der Name schon sagt; Vor allem aber wird die Aufgabe im AWT-Ereignisversand-Thread ausgeführt. Bei Verwendung von invokeLater wird die Task asynchron ausgeführt. Es gibt auch invokeAndWait, die erst zurückkehrt, wenn die Aufgabe beendet ist. Multithreaded toolkits: A failed dream?

+2

Warum kann Swing selbst nicht intern betreut werden? Warum muss der Aufrufer sich darum kümmern, wie Swing UI-Aktualisierungen handhabt? –

+4

@pure: Weil es schwierig ist, richtig zu kommen, ohne Schleusen zu sprühen (AWT hat das getan und darunter gelitten). Wenn alle Display-Updates im Dispatch-Thread durchgeführt werden müssen - auf Anwendungsebene ziemlich einfach - werden die meisten Schwachstellen beseitigt. –

14

Da GUI-Updates im Ereignisversand Thread durchgeführt werden müssen. Wenn du in einem anderen Thread arbeitest, entferne das Update in invokeLater aus deinem Thread und in den Event-Thread.

Weitere Erklärung hier: http://www.oracle.com/technetwork/java/painting-140037.html

Das intelligente, was mit großen Updates zu tun (wie eine JTable aus der Datenbank neu zu besiedeln) auf Swing ist das zugrunde liegende Modell zu erhalten, auf dem Modell in dem Thread die Updates zu tun, dann feuern Sie eine Benachrichtigung mit invokeLater ab. Das hält Ihre GUI auf Ereignisse und neu zeichnen. Wenn das Update sehr umfangreich sein wird, können Sie diese Benachrichtigungen in regelmäßigen Abständen während der Aktualisierung sogar mit invokeLater auslösen, wie jede Sekunde oder zwei.

+1

Es sieht so aus, als ob Ihr Link defekt ist –

+1

@pavelrappo - Oracle hat den Artikel entfernt, mit dem ich verlinkt habe. Ich habe einen gefunden, der anders ist, aber auch eine Erklärung enthält. –

2

SwingUtilities.invokeLater()

Ursachen doRun.run() asynchron auf dem AWT Event Dispatching Thread ausgeführt werden:

Einige Informationen über die Entscheidung nicht Swing-Thread-sicher zu machen, finden Sie hier. Dies geschieht, nachdem alle ausstehenden AWT-Ereignisse verarbeitet wurden. Diese Methode sollte verwendet werden, wenn ein Anwendungsthread die GUI aktualisieren muss.
...

7

Das Swing ist single-threaded. Jedes Update auf die UI muss aus dem so genannten EDT - Event-Dispather-Thread geschehen, der den Haupt-GUI-Thread Swing (und ich glaube AWT) verwendet. Wenn du das nicht tust, können oder werden seltsame Dinge passieren (obwohl ich Windows FOrms hier besser mag, die nur eine Ausnahme auslösen, wenn du es falsch machst).

Das heißt, Sie müssen nicht jede einzelne UI-Operation in SwingUtilities.invokeLater() umbrechen - wenn der Code, den Sie schreiben, bereits von der EDT ausgeführt wird, wird dies nicht benötigt. So benötigt die ActionListener für einen Buttonklick dies nicht. Aber ein Listener auf einem externen Objekt, der in einem anderen Thread läuft, der ein JLabel irgendwo aktualisiert - da brauchst du es.

5

Swing wurde nicht als threadsicheres GUI-Toolkit geschrieben, daher sollten alle GUI-Aktualisierungen von einem einzelnen Thread aus erfolgen, um Deadlocks zu vermeiden. In Swing ist dies der Event Dispatcher Thread (EDT).

Weitere Informationen finden Sie im Java-Lernprogramm unter Concurrent in Swing. Es verweist auch auf den Blogeintrag this, warum es schwierig ist, ein Multithread-GUI-Toolkit zu schreiben.

3

Alle Anstriche der Komponenten sollten in einem einzigen Thread ausgeführt werden, so dass sie richtig gerendert werden. So weiß die Komponente, welcher Teil bereits gemalt wurde und welcher nicht.

Wenn Sie eine "painting" -bezogene Methode (paint, update, paintComponent, show, setVisible, pack usw.) außerhalb des EDT aufrufen, versuchen Sie, in zwei verschiedenen Threads zu malen, was zu Problemen führen kann.

Wenn Sie die Benutzeroberfläche mit einem anderen Thread aktualisieren müssen, sollten Sie sie mit der Funktion invokeLater aufrufen, die sie wiederum in den EDT einfügt, sodass Sie immer noch im selben Thread malen.

Sie brauchen nicht, es zu benutzen, wenn Sie in einem Verfahren sind Codierung, die bereits im EDT läuft (zB actionPerformed oder paint oder einer von denen) Oder wenn Sie Ausführung von Code UI nicht verwandt (für Beispiel der Verarbeitung von Dateien im Hintergrund etc.)

um besser zu verstehen, all diese Konzepte lesen: The single thread rule

1

Wiederholung andere: Schaukel ist nicht Thread-sicher so ein Thread alle Updates tun muß Concurrency Probleme zu vermeiden. invokeLater ist eine Hilfsmethode, um etwas innerhalb des Ereignisverarbeitungsthreads auszuführen.

Warum Swing nicht intern tut: das ist mein Eindruck ... Ich denke, weil es zu viel wäre - jeden Ort zu überprüfen, an dem ein Update stattfindet. Es würde den Swing-Code aufblähen, die Überprüfung und Wartbarkeit des Codes beeinträchtigen.

Auf der anderen Seite ist es nicht so schwierig für eine Anwendung zu wissen, ob sie nicht innerhalb des GUI-Threads ausgeführt wird und invokeLater aufruft. Es wird sein, wenn die eigene Anwendung zuvor einen Thread gestartet hat.

Verwandte Themen