Verhindern, dass die Swing-GUI während einer Hintergrundaufgabe blockiert

Lesezeit: 7 Minuten

Verhindern dass die Swing GUI wahrend einer Hintergrundaufgabe blockiert
Simonw

Ich habe eine Swing-Anwendung, die eine Liste von Objekten speichert. Wenn der Benutzer auf eine Schaltfläche klickt,

Ich möchte zwei Operationen für jedes Objekt in der Liste ausführen und dann, sobald dies abgeschlossen ist, die Ergebnisse in einem JPanel grafisch darstellen. Ich habe SwingWorker, Callable & Runnable ausprobiert, um die Verarbeitung durchzuführen, aber egal, was ich tue, während der Verarbeitung der Liste (die bis zu ein paar Minuten dauern kann, da sie IO-gebunden ist), ist die GUI blockiert.

Ich habe das Gefühl, dass es wahrscheinlich an der Art und Weise liegt, wie ich die Threads aufrufe oder so oder könnte es mit der Grafikfunktion zu tun haben? Das ist nicht eingefädelt, da es sehr schnell ist.

Ich muss auch die beiden Verarbeitungsschritte der Reihe nach durchführen. Wie kann also am besten sichergestellt werden, dass der zweite auf den ersten gewartet hat? Ich habe join() verwendet, und dann

while(x.isAlive())  
{  
        Thread.sleep(1000);  
}

versuchen, dies sicherzustellen, aber ich mache mir Sorgen, dass dies auch die Ursache für mein Problem sein könnte.

Ich habe überall nach Hinweisen gesucht, aber da ich keine finden kann, bin ich mir sicher, dass ich hier etwas Dummes mache.

  • Es kann hilfreich sein, wenn Sie Code einfügen, der zeigt, wie Sie SwingWorker verwenden.

    – Matt Solnit

    2. Juni ’09 um 18:00

  • Einverstanden; Zeigen Sie uns den problematischen Code.

    – Rauben

    3. Juni ’09 um 23:27

Verhindern dass die Swing GUI wahrend einer Hintergrundaufgabe blockiert
jjnguy

Das Problem ist, dass Ihre lang laufende Aufgabe den Thread blockiert, der die Benutzeroberfläche reaktionsfähig hält.

Was Sie tun müssen, ist, die lang andauernde Aufgabe in einen anderen Thread zu legen.

Einige gängige Methoden hierfür sind die Verwendung von Timern oder a SwingWorker.

Der Java-Tutorials haben viele Informationen zu diesen Dingen in ihrem Unterricht in Parallelität.

Um sicherzustellen, dass die erste Aufgabe vor der zweiten abgeschlossen ist, legen Sie einfach beide in denselben Thread. Auf diese Weise müssen Sie sich keine Sorgen machen, dass zwei verschiedene Threads die richtige Zeit haben.

Hier ist eine Beispielimplementierung eines SwingWorkerFür Ihren Fall:

public class YourTaskSwingWorkerSwingWorker extends SwingWorker<List<Object>, Void> {
    private List<Object> list
    public YourClassSwingWorker(List<Object> theOriginalList){
        list = theOriginalList;
    }

    @Override
    public List<Object> doInBackground() {
        // Do the first opperation on the list
        // Do the second opperation on the list

        return list;
    }

    @Override
    public void done() {
        // Update the GUI with the updated list.
    }
}

Um diesen Code zu verwenden, wenn das Ereignis zum Ändern der Liste ausgelöst wird, erstellen Sie ein neues SwingWorker und sagen Sie ihm, dass es starten soll.

  • Ich bin mir ziemlich sicher, dass die Frage bereits Threads und SwingWorker erwähnt hat. Außerdem führt SwingUtilities.invokeLater() Dinge im GUI-Thread aus.

    – Machtlord

    2. Juni ’09 um 17:52

  • Ja, ich habe eine Art allgemeine Antwort auf das Einfädeln gegeben … irgendwie scheiße

    – jjnguy

    2. Juni ’09 um 17:54

  • Ich war gestern zu faul, das Javadoc nachzuschlagen, aber ich sehe jetzt, dass der zweite Typparameter nur als Parameter für publish() und process() verwendet wird. Ich ziehe meinen ersten Kommentar zurück.

    – Michael myers
    ♦.

    3. Juni ’09 um 15:23

  • SwingUtilities.invokeLater() führt Aufgaben im Event-Dispatch-Thread aus, was zu einem unbestimmten zukünftigen Zeitpunkt das gleiche Problem verursacht. Schlechter Rat.

    – Rauben

    3. Juni ’09 um 23:24

  • Genau das was ich gesucht habe! Ich bin mit meinen Google-Kenntnissen und SE heute zufrieden!

    – Wahnsinn

    18. November ’14 um 11:23

1641965953 811 Verhindern dass die Swing GUI wahrend einer Hintergrundaufgabe blockiert
Bill K

Sie geben den Schwenkfaden nicht richtig zurück. Mir ist klar, dass Sie Callable/Runnable verwenden, aber ich vermute, dass Sie es nicht richtig machen (obwohl Sie nicht genug Code gepostet haben, um es sicher zu wissen).

Die Grundstruktur wäre:

swingMethod() { // Okay, this is a button callback, we now own the swing thread
    Thread t=new Thread(new ActuallyDoStuff());
    t.start();
}

public class ActuallyDoStuff() implements Runnable {
    public void run() {
        // this is where you actually do the work
    }
}

Das ist mir gerade eingefallen, aber ich vermute, dass Sie entweder thread.start nicht ausführen und stattdessen die run-Methode direkt aufrufen, oder Sie tun etwas anderes in der ersten Methode, die es sperrt ( wie thread.join). Beides würde den Schwungfaden nicht freigeben. Die erste Methode MUSS schnell zurückkehren, die Methode run() kann so lange dauern, wie sie möchte.

Wenn Sie in der ersten Methode einen thread.join durchführen, wird der Thread NICHT an das System zurückgegeben!

Bearbeiten: (eigentlich zweite Bearbeitung) Ich denke, um auf das Problem zu sprechen, das Sie tatsächlich fühlen – Sie möchten vielleicht mehr in Bezug auf ein Modell- / Ansichts- / Controller-System denken. Der Code, den Sie schreiben, ist der Controller (die Ansicht wird im Allgemeinen als die Komponenten auf dem Bildschirm angesehen – Ansicht/Controller sind normalerweise sehr eng gebunden).

Wenn Ihr Controller das Ereignis empfängt, sollte er die Arbeit an Ihr Modell übergeben. Die Ansicht ist dann aus dem Bild. Es wartet nicht auf das Modell, es ist einfach fertig.

Wenn Ihr Modell fertig ist, muss es den Controller anweisen, etwas anderes zu tun. Dies geschieht über eine der Aufrufmethoden. Dadurch wird die Kontrolle wieder an den Controller übertragen und Sie können sich auf den Weg machen. Wenn man so darüber nachdenkt, fühlt es sich nicht so sperrig an, die Kontrolle zu trennen und sie absichtlich hin und her zu geben, und es ist tatsächlich sehr üblich, dies auf diese Weise zu tun.

  • In meinem Fall habe ich thread.run() anstelle von thread.start() verwendet, und das führte mich zur GUI-Sperre. Das Setzen von thread.start() hat das Problem behoben.

    – Alexey

    8. Apr. ’15 um 18:32

Es hört sich so an, als ob das Problem darin bestehen könnte, dass Sie darauf warten, dass die Threads innerhalb des GUI-Threads beendet werden. Ihr GUI-Thread sollte nicht auf diese Threads warten, sondern die Worker-Threads sollten eine Methode im GUI-Thread aufrufen, die ein Flag setzt. Wenn beide Flags gesetzt sind, wissen Sie, dass beide Threads beendet sind und Sie können das Diagramm erstellen.

Ich kann nicht wirklich mit dem Swing-Threading-Modell sprechen, aber:

Ich muss auch die beiden Verarbeitungsschritte der Reihe nach durchführen. Wie kann also am besten sichergestellt werden, dass der zweite auf den ersten gewartet hat?

Für diese Art von Funktionalität würde ich vorschlagen, dass Sie zwei Worker-Threads erstellen und einen JMS-Broker einbetten. Liefern Sie Arbeit an die beiden Threads, indem Sie Nachrichten an JMS-Warteschlangen übergeben, aus denen sie lesen. Es steht Ihrem GUI-Thread frei, die Warteschlangen zu untersuchen, um festzustellen, wann die Arbeiten ausgeführt werden, und um den aktuellen Stand in Ihrer Benutzeroberfläche darzustellen.

Verhindern dass die Swing GUI wahrend einer Hintergrundaufgabe blockiert
Simonw

Die Lösung für mein Problem war eine Mischung aus jjnguy und Bill Ks Antworten, also vielen Dank dafür. Ich musste Threads in einem SwingWorker wie folgt verwenden:

public class Worker extends SwingWorker<Void, Void>   
{  
    private List<Object> list;  
    public YourClassSwingWorker(List<Object> theOriginalList){  
        list = theOriginalList;  
    }

    @Override
    public List<Object> doInBackground() {
        Thread t = new Thread(new ProcessorThread(list));  
        t.start();
    }

    @Override
    public void done() {
        // draw graph on GUI
    }
}  
class ProcessorThread implements Runnable {  
    //do lots of IO stuff  
    Thread t2 = new Thread(new SecondProcess());
    t2.start();  
}

Dadurch wurde sichergestellt, dass die gesamte Arbeit von Worker-Threads außerhalb der grafischen Benutzeroberfläche ausgeführt wurde und dass nicht der SwingWorker selbst die gesamte Arbeit erledigte, was möglicherweise ein Problem gewesen wäre.

  • Whoa whoa whoa! Warum erzeugen Sie einen Thread aus dem SwingWorker? SwingWorker (wenn sie mit der Methode execute() gestartet werden) werden nicht auf dem GUI-Thread ausgeführt, daher sollte es keinen Grund geben, hier einen weiteren Thread zu erstellen.

    – Michael myers
    ♦.

    10. Juni ’09 um 18:01

  • Ich muss es anfangs falsch gemacht haben, denn das war die einzige Lösung, die für mich funktioniert hat

    – Simonw

    11. Juni ’09 um 0:33

  • Whoa whoa whoa! Warum erzeugen Sie einen Thread aus dem SwingWorker? SwingWorker (wenn sie mit der Methode execute() gestartet werden) werden nicht auf dem GUI-Thread ausgeführt, daher sollte es keinen Grund geben, hier einen weiteren Thread zu erstellen.

    – Michael myers
    ♦.

    10. Juni ’09 um 18:01

  • Ich muss es anfangs falsch gemacht haben, denn das war die einzige Lösung, die für mich funktioniert hat

    – Simonw

    11. Juni ’09 um 0:33

.

421350cookie-checkVerhindern, dass die Swing-GUI während einer Hintergrundaufgabe blockiert

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy