CodeGym /Kurse /JAVA 25 SELF /EDT-Thread und lang andauernde Operationen in der UI

EDT-Thread und lang andauernde Operationen in der UI

JAVA 25 SELF
Level 50, Lektion 4
Verfügbar

1. Was ist der EDT (Event Dispatch Thread)

In grafischen Java-Anwendungen — sei es Swing oder JavaFX — werden alle Benutzeraktionen (Klicks, Tasten) sowie das Neuzeichnen von Fenstern in einem speziellen Thread namens EDT (Event Dispatch Thread) verarbeitet.

Wozu wird er benötigt? UI‑Komponenten in Java sind nicht threadsicher. Um Race Conditions und Artefakte zu vermeiden, werden alle Änderungen der Oberfläche strikt an genau einer Stelle ausgeführt — im EDT. Das ist wie eine Kasse mit nur einem Kassierer: Am selben Beleg können nicht gleichzeitig mehrere Personen arbeiten.

In Swing führt der EDT Ereignis-Handler und das Neuzeichnen der Komponenten aus (z. B. actionPerformed). In JavaFX ist das Pendant der JavaFX Application Thread, auf dem UI‑Updates und Handler wie setOnAction ausgeführt werden.

2. Das Problem „langer Operationen“ in der UI

Was passiert, wenn man im EDT eine lang andauernde Operation startet?

Wenn der Benutzer eine Schaltfläche drückt, läuft der Handler (z. B. actionPerformed oder setOnAction) im EDT. Starten Sie darin eine schwere Aufgabe (Lesen einer großen Datei, Netzwerkaufruf, aufwendige Berechnungen), friert die gesamte UI ein:

  • Das Fenster reagiert nicht mehr auf Klicks und Tasten.
  • Das Neuzeichnen funktioniert nicht mehr — beim Verschieben „friert“ das Fenster ein.
  • Der Benutzer glaubt, das Programm sei „abgestürzt“.

Beispiel für falschen Code (Swing):

button.addActionListener(e -> {
    // Lange Operation direkt im EDT!
    longOperation(); // Zum Beispiel das Lesen einer großen Datei
    label.setText("Fertig!");
});

Ergebnis: Solange longOperation() läuft, reagiert das Fenster nicht auf den Benutzer.

Warum ist das so? Der EDT verarbeitet Aufgaben nacheinander und kann immer nur eine gleichzeitig ausführen. Solange er mit Ihrer langen Operation beschäftigt ist, kann er weder Klicks noch Neuzeichnen bearbeiten.

3. Lösung: Lange Operationen nur in Hintergrund-Threads

Prinzip:

  • Alle lang andauernden Operationen gehören in Hintergrund-Threads.
  • Alle UI‑Änderungen — nur im EDT/JavaFX Application Thread.

Eine lange Operation in einem separaten Thread starten

Beispiel (Swing):

button.addActionListener(e -> {
    new Thread(() -> {
        longOperation(); // Läuft in einem Hintergrund-Thread
        // Jetzt die UI aktualisieren — aber nur aus dem EDT!
        SwingUtilities.invokeLater(() -> label.setText("Fertig!"));
    }).start();
});

Beispiel (JavaFX):

button.setOnAction(e -> {
    new Thread(() -> {
        longOperation();
        // UI über Platform.runLater aktualisieren
        Platform.runLater(() -> label.setText("Fertig!"));
    }).start();
});

Wie aktualisiert man die UI aus einem Hintergrund-Thread?

  • Swing: verwenden Sie SwingUtilities.invokeLater(Runnable) — die Aufgabe landet in der Warteschlange des EDT.
  • JavaFX: verwenden Sie Platform.runLater(Runnable) — die Aufgabe wird im JavaFX Application Thread ausgeführt.

Warum kann man nicht einfach label.setText(...) aus einem Hintergrund-Thread aufrufen? Weil das die Thread-Sicherheit der UI verletzt: Komponenten dürfen nur aus dem UI‑Thread geändert werden.

Spezielle Klassen für Hintergrundaufgaben

In realen Anwendungen muss man häufig Fortschritt anzeigen, Abbruch erlauben und Fehler behandeln. Dafür gibt es:

  • SwingWorker<T, V> — für Swing;
  • Task<V>, Service<V> — für JavaFX.

Beispiel (JavaFX Task):

Task<Void> task = new Task<>() {
    @Override
    protected Void call() throws Exception {
        longOperation();
        // Fortschritt kann aktualisiert werden: updateProgress(...)
        return null;
    }
};

task.setOnSucceeded(e -> label.setText("Fertig!"));
task.setOnFailed(e -> label.setText("Fehler!"));

new Thread(task).start();

Vorteile: Fortschritt, Abbruch, Ereignisse für Erfolg/Fehler. UI‑Änderungen — über sichere Methoden (updateMessage, updateProgress) oder Handler (setOnSucceeded u. a.).

4. Richtige und falsche Muster

Falsch: lange Operationen im Ereignis-Handler

button.setOnAction(e -> longOperation()); // Die UI friert ein!

Richtig: lange Operationen in einem separaten Thread

button.setOnAction(e -> new Thread(() -> longOperation()).start());

Noch besser: Task/Worker verwenden

JavaFX:

button.setOnAction(e -> {
    Task<Void> task = new Task<>() {
        @Override
        protected Void call() throws Exception {
            longOperation();
            return null;
        }
    };
    task.setOnSucceeded(ev -> label.setText("Fertig!"));
    new Thread(task).start();
});

Swing:

button.addActionListener(e -> {
    SwingWorker<Void, Void> worker = new SwingWorker<>() {
        @Override
        protected Void doInBackground() throws Exception {
            longOperation();
            return null;
        }
        @Override
        protected void done() {
            label.setText("Fertig!");
        }
    };
    worker.execute();
});

5. Praxis: Beispiel für das Laden einer Datei

JavaFX:

button.setOnAction(e -> {
    Task<String> task = new Task<>() {
        @Override
        protected String call() throws Exception {
            // Simulation eines langwierigen Ladevorgangs
            Thread.sleep(2000);
            return "Datei geladen!";
        }
    };
    task.setOnSucceeded(ev -> label.setText(task.getValue()));
    new Thread(task).start();
});

Swing:

button.addActionListener(e -> {
    SwingWorker<String, Void> worker = new SwingWorker<>() {
        @Override
        protected String doInBackground() throws Exception {
            Thread.sleep(2000);
            return "Datei geladen!";
        }
        @Override
        protected void done() {
            try {
                label.setText(get());
            } catch (Exception ex) {
                label.setText("Fehler!");
            }
        }
    };
    worker.execute();
});

6. Typische Fehler beim Arbeiten mit dem EDT und langen Operationen

Fehler Nr. 1: Lange Operation im EDT. Die gesamte Anwendung „friert ein“, das Fenster reagiert nicht, der Benutzer denkt, das Programm sei abgestürzt.

Fehler Nr. 2: Versuch, die UI aus einem Hintergrund-Thread zu aktualisieren. Das Verletzen der Thread-Sicherheit der UI kann zu Bugs, Artefakten und Abstürzen führen. Verwenden Sie SwingUtilities.invokeLater oder Platform.runLater.

Fehler Nr. 3: Keine Fehlerbehandlung in der Hintergrundaufgabe. Ausnahmen „verschwinden“, der Benutzer weiß nicht, was schiefgelaufen ist. In Swing — überschreiben Sie done() und lesen Sie get(); in JavaFX — registrieren Sie setOnFailed.

Fehler Nr. 4: Keine Möglichkeit, die lange Operation abzubrechen. Der Benutzer kann Laden/Berechnung nicht abbrechen. Nutzen Sie die Abbruchunterstützung (SwingWorker.cancel, Task.cancel) und prüfen Sie Abbruch-Flags innerhalb der Aufgabe.

Fehler Nr. 5: Keine Fortschrittsanzeige. Der Benutzer denkt, das Programm sei „eingefroren“. In Swing — verwenden Sie Ergebnisveröffentlichung und Fortschrittsbalken zusammen mit SwingWorker; in JavaFX — updateProgress und visuelle Indikatoren.

1
Aufgabe
JAVA 25 SELF, Level 50, Lektion 4
Gesperrt
Hängendes Lasersteuerpult 💥
Hängendes Lasersteuerpult 💥
1
Aufgabe
JAVA 25 SELF, Level 50, Lektion 4
Gesperrt
Reaktionsschnelle Lasersteuerung ✨
Reaktionsschnelle Lasersteuerung ✨
1
Umfrage/Quiz
Events und Event-Handling, Level 50, Lektion 4
Nicht verfügbar
Events und Event-Handling
Events und Event-Handling
Kommentare
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION