Ich habe ein Objekt mit einer Methode namens StartDownload()
, die drei Threads startet.
Wie erhalte ich eine Benachrichtigung, wenn die Ausführung jedes Threads abgeschlossen ist?
Gibt es eine Möglichkeit festzustellen, ob einer (oder alle) Threads fertig sind oder noch ausgeführt werden?
java
multithreading
Ricardo Felgueiras
quelle
quelle
Antworten:
Es gibt verschiedene Möglichkeiten, dies zu tun:
Wie implementiere ich Idee 5? Eine Möglichkeit besteht darin, zuerst eine Schnittstelle zu erstellen:
Erstellen Sie dann die folgende Klasse:
und dann wird jeder Ihrer Threads erweitert
NotifyingThread
und anstatt ihn zu implementierenrun()
, wird er implementiertdoRun()
. Wenn sie abgeschlossen sind, benachrichtigen sie automatisch jeden, der auf eine Benachrichtigung wartet.Schließlich ändern Sie in Ihrer Hauptklasse - der Klasse, die alle Threads startet (oder zumindest das Objekt, das auf eine Benachrichtigung wartet) - diese Klasse
implement ThreadCompleteListener
und fügen sich unmittelbar nach dem Erstellen jedes Threads der Liste der Listener hinzu:Wenn jeder Thread beendet wird, wird Ihre
notifyOfThreadComplete
Methode mit der gerade abgeschlossenen (oder abgestürzten) Thread-Instanz aufgerufen.Beachten Sie, dass es besser wäre,
implements Runnable
alsextends Thread
fürNotifyingThread
das Erweitern von Threads in neuem Code normalerweise nicht zu empfehlen. Aber ich codiere auf Ihre Frage. Wenn Sie dieNotifyingThread
zu implementierende Klasse ändernRunnable
, müssen Sie einen Teil Ihres Codes ändern, der Threads verwaltet, was ziemlich einfach ist.quelle
notify
Methode nicht innerhalb derrun
Methode, sondern danach aufzurufen .Lösung mit CyclicBarrier
label0 - Die zyklische Barriere wird mit einer Anzahl von Parteien erstellt, die der Anzahl der ausgeführten Threads plus einer für den Hauptausführungsthread entspricht (in dem startDownload () ausgeführt wird).
Etikett 1 - n-ter DownloadingThread betritt den Warteraum
Label 3 - NUMBER_OF_DOWNLOADING_THREADS haben den Warteraum betreten. Der Hauptthread der Ausführung gibt sie frei, um ihre Download-Jobs mehr oder weniger zur gleichen Zeit auszuführen
Etikett 4 - Hauptthread der Ausführung betritt den Warteraum. Dies ist der "schwierigste" Teil des Codes, den es zu verstehen gilt. Es spielt keine Rolle, welcher Thread zum zweiten Mal in den Warteraum gelangt. Es ist wichtig, dass jeder Thread, der zuletzt den Raum betritt, sicherstellt, dass alle anderen Download-Threads ihre Download-Jobs beendet haben.
label 2 - n-th DownloadingThread hat den Download-Auftrag beendet und betritt den Warteraum. Wenn es der letzte ist, dh bereits NUMBER_OF_DOWNLOADING_THREADS eingegeben hat, einschließlich des Hauptthreads der Ausführung, setzt der Hauptthread seine Ausführung erst fort, wenn alle anderen Threads den Download abgeschlossen haben.
quelle
Sie sollten wirklich eine Lösung bevorzugen, die verwendet
java.util.concurrent
. Finden und lesen Sie Josh Bloch und / oder Brian Goetz zum Thema.Wenn Sie
java.util.concurrent.*
Threads nicht direkt verwenden und die Verantwortung dafür übernehmen, sollten Sie wahrscheinlich verwenden, umjoin()
zu wissen, wann ein Thread fertig ist. Hier ist ein super einfacher Rückrufmechanismus. Erweitern Sie zuerst dieRunnable
Schnittstelle, um einen Rückruf zu erhalten:Erstellen Sie dann einen Executor, der Ihre ausführbare Datei ausführt, und rufen Sie zurück, wenn dies erledigt ist.
Die andere offensichtliche Sache, die Sie Ihrer
CallbackRunnable
Schnittstelle hinzufügen müssen, ist ein Mittel, um Ausnahmen zu behandeln.public void uncaughtException(Throwable e);
Fügen Sie also möglicherweise eine Zeile ein und installieren Sie in Ihrem Executor einen Thread.UncaughtExceptionHandler, um Sie an diese Schnittstellenmethode zu senden.Aber all das zu tun, fängt wirklich an zu riechen
java.util.concurrent.Callable
. Sie sollten sich wirklich die Verwendung ansehen,java.util.concurrent
wenn Ihr Projekt dies zulässt.quelle
runner.join()
und dann den gewünschten Code danach, da Sie wissen, dass der Thread beendet ist. Ist es nur so, dass Sie diesen Code als eine Eigenschaft der ausführbaren Datei definieren können, sodass Sie für verschiedene ausführbare Dateien unterschiedliche Funktionen haben können?runner.join()
ist der direkteste Weg zu warten. Ich ging davon aus, dass das OP seinen Hauptaufrufthread nicht blockieren wollte, da sie darum baten, für jeden Download "benachrichtigt" zu werden, der in beliebiger Reihenfolge abgeschlossen werden konnte. Dies bot eine Möglichkeit, asynchron benachrichtigt zu werden.Möchten Sie warten, bis sie fertig sind? Verwenden Sie in diesem Fall die Join-Methode.
Es gibt auch die Eigenschaft isAlive, wenn Sie sie nur überprüfen möchten.
quelle
Thread
tostart
, was der Thread tut, aber der Aufruf kehrt sofort zurück.isAlive
sollte ein einfacher Flaggentest sein, aber als ich ihn googelte, war die Methodenative
.Sie können die Thread-Instanz mit getState () abfragen, das eine Instanz der Thread.State-Enumeration mit einem der folgenden Werte zurückgibt:
Ich denke jedoch, es wäre ein besseres Design, einen Master-Thread zu haben, der darauf wartet, dass die 3 Kinder fertig sind. Der Master würde dann die Ausführung fortsetzen, wenn die anderen 3 fertig sind.
quelle
Sie können das
Executors
Objekt auch verwenden , um einen ExecutorService- Thread-Pool zu erstellen . Verwenden Sie dann dieinvokeAll
Methode, um jeden Ihrer Threads auszuführen und Futures abzurufen. Dies wird blockiert, bis alle die Ausführung beendet haben. Ihre andere Möglichkeit wäre, jeden einzelnen mithilfe des Pools auszuführen und dannawaitTermination
zum Blockieren aufzurufen , bis die Ausführung des Pools abgeschlossen ist. Rufenshutdown
Sie einfach () auf, wenn Sie mit dem Hinzufügen von Aufgaben fertig sind.quelle
Viele Dinge wurden in den letzten 6 Jahren an der Multithreading-Front geändert.
Anstatt die
join()
API zu verwenden und zu sperren, können Sie sie verwenden1. ExecutorService
invokeAll()
API2. CountDownLatch
3. ForkJoinPool oder
newWorkStealingPool()
in Executors ist eine andere Möglichkeit4. Durchlaufen Sie alle
Future
Aufgaben ab dem SendenExecutorService
und überprüfen Sie den Status, indem Sie den Aufrufget()
desFuture
Objekts blockierenSchauen Sie sich verwandte SE-Fragen an:
Wie kann man auf einen Thread warten, der seinen eigenen Thread erzeugt?
Ausführende: Wie kann ich synchron warten, bis alle Aufgaben abgeschlossen sind, wenn Aufgaben rekursiv erstellt werden?
quelle
Ich würde vorschlagen, sich den Javadoc für die Thread- Klasse anzusehen .
Sie haben mehrere Mechanismen zur Thread-Manipulation.
Ihr Haupt-Thread könnte
join()
die drei Threads seriell und würde dann nicht fortfahren, bis alle drei fertig sind.Fragen Sie in regelmäßigen Abständen den Thread-Status der erzeugten Threads ab.
Lege alle gespawnten Threads in einen separaten
ThreadGroup
und frage denactiveCount()
auf abThreadGroup
und warte, bis er auf 0 kommt.Richten Sie eine benutzerdefinierte Rückruf- oder Listener-Schnittstelle für die Kommunikation zwischen Threads ein.
Ich bin mir sicher, dass es noch viele andere Möglichkeiten gibt, die mir noch fehlen.
quelle
Hier ist eine Lösung, die einfach, kurz, leicht zu verstehen ist und perfekt für mich funktioniert. Ich musste auf den Bildschirm zeichnen, wenn ein anderer Thread endet. konnte aber nicht, weil der Haupt-Thread die Kontrolle über den Bildschirm hat. So:
(1) Ich habe die globale Variable erstellt:
boolean end1 = false;
Der Thread setzt sie beim Beenden auf true. Dies wird im Mainthread von der "postDelayed" -Schleife erfasst, wo darauf geantwortet wird.(2) Mein Thread enthält:
(3) Glücklicherweise wird "postDelayed" im Hauptthread ausgeführt, sodass der andere Thread einmal pro Sekunde überprüft wird. Wenn der andere Thread endet, kann dies beginnen, was auch immer wir als nächstes tun möchten.
(4) Starten Sie das Ganze schließlich irgendwo in Ihrem Code, indem Sie Folgendes aufrufen:
quelle
Ich denke, der einfachste Weg ist,
ThreadPoolExecutor
Klasse zu benutzen .Das ist genau das, was wir brauchen. Wir werden überschreiben
afterExecute()
, um Rückrufe zu erhalten, nachdem jeder Thread abgeschlossen ist, und überschreiben, umterminated()
zu wissen, wann alle Threads abgeschlossen sind.Also hier ist, was Sie tun sollten
Erstellen Sie einen Executor:
Und starten Sie Ihre Threads:
Innerhalb der Methode
informUiThatWeAreDone();
tun Sie alles, was Sie tun müssen, wenn alle Threads fertig sind, z. B. die Benutzeroberfläche aktualisieren.HINWEIS: Vergessen Sie nicht, zu verwenden
synchronized
Methoden zu verwenden, da Sie Ihre Arbeit parallel ausführen und SEHR VORSICHTIG sind, wenn Sie diesynchronized
Methode von einer anderensynchronized
Methode aus aufrufen ! Dies führt häufig zu DeadlocksHoffe das hilft!
quelle
Sie können auch SwingWorker verwenden, das über eine integrierte Unterstützung für Eigenschaftsänderungen verfügt. Ein Beispiel für einen Listener für Statusänderungen finden Sie unter addPropertyChangeListener () oder get () .
quelle
Schauen Sie sich die Java-Dokumentation für die Thread-Klasse an. Sie können den Status des Threads überprüfen. Wenn Sie die drei Threads in Mitgliedsvariablen einfügen, können alle drei Threads die Zustände des anderen lesen.
Sie müssen jedoch etwas vorsichtig sein, da dies zu Rennbedingungen zwischen den Threads führen kann. Versuchen Sie einfach, komplizierte Logik zu vermeiden, die auf dem Status der anderen Threads basiert. Vermeiden Sie auf jeden Fall, dass mehrere Threads in dieselben Variablen schreiben.
quelle