Kann mir jemand helfen zu verstehen, was Java CountDownLatch
ist und wann ich es verwenden soll?
Ich habe keine klare Vorstellung davon, wie dieses Programm funktioniert. Soweit ich weiß, beginnen alle drei Threads gleichzeitig und jeder Thread ruft nach 3000 ms CountDownLatch auf. Der Countdown wird also nacheinander verringert. Nachdem die Verriegelung Null geworden ist, gibt das Programm "Abgeschlossen" aus. Vielleicht ist die Art, wie ich verstanden habe, falsch.
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
class Processor implements Runnable {
private CountDownLatch latch;
public Processor(CountDownLatch latch) {
this.latch = latch;
}
public void run() {
System.out.println("Started.");
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
latch.countDown();
}
}
// ------------------------------------------------ -----
public class App {
public static void main(String[] args) {
CountDownLatch latch = new CountDownLatch(3); // coundown from 3 to 0
ExecutorService executor = Executors.newFixedThreadPool(3); // 3 Threads in pool
for(int i=0; i < 3; i++) {
executor.submit(new Processor(latch)); // ref to latch. each time call new Processes latch will count down by 1
}
try {
latch.await(); // wait until latch counted down to 0
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Completed.");
}
}
Antworten:
Ja, du hast richtig verstanden.
CountDownLatch
funktioniert nach dem Latch-Prinzip, der Hauptfaden wartet, bis das Tor geöffnet ist. Ein Thread wartet auf n Threads, die beim Erstellen des Threads angegeben wurdenCountDownLatch
.Jeder Thread, normalerweise der Hauptthread der Anwendung, der aufruft
CountDownLatch.await()
, wartet, bis die Anzahl Null erreicht oder von einem anderen Thread unterbrochen wird. Alle anderen Threads müssen durch Aufrufen heruntergezählt werden,CountDownLatch.countDown()
sobald sie abgeschlossen oder bereit sind.Sobald die Zählung Null erreicht, wird der wartende Thread fortgesetzt. Einer der Nachteile / Vorteile von
CountDownLatch
ist, dass es nicht wiederverwendbar ist: Sobald die Zählung Null erreicht, können Sie nichtCountDownLatch
mehr verwenden.Bearbeiten:
Verwenden Sie diese Option,
CountDownLatch
wenn ein Thread (wie der Haupt-Thread) warten muss, bis ein oder mehrere Threads abgeschlossen sind, bevor die Verarbeitung fortgesetzt werden kann.Ein klassisches Beispiel für die Verwendung
CountDownLatch
in Java ist eine serverseitige Java-Kernanwendung, die eine Dienstarchitektur verwendet, bei der mehrere Dienste von mehreren Threads bereitgestellt werden und die Anwendung erst mit der Verarbeitung beginnen kann, wenn alle Dienste erfolgreich gestartet wurden.Die Frage von PS OP hat ein ziemlich einfaches Beispiel, daher habe ich keines aufgenommen.
quelle
One thread waits for n number of threads specified while creating CountDownLatch in Java
. Wenn Sie einen solchen Mechanismus benötigen, ist es ratsam, ihn zu verwendenCyclicBarrier
. Der grundlegende konzeptionelle Unterschied zwischen diesen beiden, wie in angegeben,Java concurrency in Practice
ist :Latches are for waiting for events; barriers are for waiting for other threads
.cyclicBarrier.await()
geht in einen blockierenden Zustand.CountDownLatch
In Java handelt es sich um eine Art Synchronisierer, mit dem manThread
auf ein oder mehrereThread
Sekunden warten kann, bevor die Verarbeitung beginnt.CountDownLatch
funktioniert nach dem Latch-Prinzip, der Thread wartet, bis das Gate geöffnet ist. Ein Thread wartet auf dien
Anzahl der beim Erstellen angegebenen ThreadsCountDownLatch
.z.B
final CountDownLatch latch = new CountDownLatch(3);
Hier setzen wir den Zähler auf 3.
Jeder Thread, normalerweise der Hauptthread der Anwendung, der aufruft
CountDownLatch.await()
, wartet, bis die Anzahl Null erreicht oder von einem anderen unterbrochen wirdThread
. Alle anderen Threads müssen einen Countdown durchführen, indem sie aufrufen,CountDownLatch.countDown()
sobald sie abgeschlossen oder für den Job bereit sind. Sobald die Zählung Null erreicht,Thread
beginnt das Warten.Hier wird die Anzahl nach
CountDownLatch.countDown()
Methode dekrementiert .Der
Thread
Aufruf derawait()
Methode wartet, bis die anfängliche Zählung Null erreicht.Um die Zählung auf Null zu setzen, müssen andere Threads die
countDown()
Methode aufrufen . Sobald die Anzahl Null wird, wird der Thread, der dieawait()
Methode aufgerufen hat , fortgesetzt (Start der Ausführung).Der Nachteil von
CountDownLatch
ist, dass es nicht wiederverwendbar ist: Sobald der Zähler Null wird, ist es nicht mehr verwendbar.quelle
new CountDownLatch(3)
da wir 3 Threads aus demnewFixedThreadPool
definierten haben?NikolaB hat es sehr gut erklärt. Ein Beispiel wäre jedoch hilfreich zu verstehen. Hier ist ein einfaches Beispiel ...
quelle
Es wird verwendet, wenn mehr als ein Thread warten soll, um seine Aufgabe abzuschließen. Es ist ähnlich, Threads zu verbinden.
Wo wir CountDownLatch verwenden können
Stellen Sie sich ein Szenario vor, in dem drei Threads "A", "B" und "C" erforderlich sind und der Thread "C" nur gestartet werden soll, wenn die Threads "A" und "B" ihre Aufgabe abgeschlossen oder teilweise abgeschlossen haben.
Es kann auf ein reales IT-Szenario angewendet werden
Stellen Sie sich ein Szenario vor, in dem der Manager Module zwischen Entwicklungsteams (A und B) aufteilt und sie dem QA-Team nur dann zum Testen zuweisen möchte, wenn beide Teams ihre Aufgabe abgeschlossen haben.
Die Ausgabe des obigen Codes lautet:
Aufgabe dem Entwicklungsteam devB zugewiesen
Aufgabe dem Entwicklungsteam devA zugewiesen
Aufgabe vom Entwicklungsteam devB erledigt
Aufgabe vom Entwicklungsteam devA erledigt
Aufgabe dem QA-Team zugewiesen
Aufgabe vom QA-Team erledigt
Hier wartet die Methode await () darauf , dass das Countdownlatch-Flag 0 wird, und die countDown () -Methode verringert das Countdownlatch-Flag um 1.
Einschränkung von JOIN: Das obige Beispiel kann auch mit JOIN erreicht werden, JOIN kann jedoch nicht in zwei Szenarien verwendet werden:
quelle
Mit CoundDownLatch können Sie einen Thread warten lassen, bis alle anderen Threads mit ihrer Ausführung fertig sind.
Pseudocode kann sein:
quelle
Ein gutes Beispiel für die Verwendung von so etwas ist der Java Simple Serial Connector, der auf serielle Schnittstellen zugreift. Normalerweise schreiben Sie etwas in den Port, und asynchron in einem anderen Thread antwortet das Gerät auf einem SerialPortEventListener. Normalerweise möchten Sie nach dem Schreiben an den Port eine Pause einlegen, um auf die Antwort zu warten. Die manuelle Behandlung der Thread-Sperren für dieses Szenario ist äußerst schwierig, die Verwendung von Countdownlatch ist jedoch einfach. Bevor Sie denken, dass Sie es anders machen können, achten Sie auf die Rennbedingungen, an die Sie nie gedacht haben !!
Pseudocode:
quelle
Wenn Sie nach Ihrem Aufruf von latch.countDown () ein Debug hinzufügen, kann dies Ihnen helfen, das Verhalten besser zu verstehen.
Die Ausgabe zeigt den dekrementierten Count an. Diese 'Anzahl' ist effektiv die Anzahl der ausführbaren Aufgaben (Prozessorobjekte), die Sie gestartet haben und für die countDown () nicht aufgerufen wurde. Daher wird der Hauptthread beim Aufruf von latch.await () blockiert.
quelle
Aus der Oracle-Dokumentation zu CountDownLatch :
A
CountDownLatch
wird mit einer bestimmten Anzahl initialisiert. Dieawait
Methoden blockieren, bis die aktuelle Anzahl aufgrund von Aufrufen dercountDown()
Methode Null erreicht. Danach werden alle wartenden Threads freigegeben und alle nachfolgenden Aufrufe von wait warten sofort zurück. Dies ist ein One-Shot-Phänomen - die Zählung kann nicht zurückgesetzt werden.Ein
CountDownLatch
mit einer Zählung von eins initialisiertes dient als einfaches Ein / Aus-Latch oder Gate: Alle aufrufenden Threads warten auf das Warten am Gate, bis es von einem Thread geöffnet wird, der countDown () aufruft.Eine
CountDownLatch
auf N initialisierte Option kann verwendet werden, um einen Thread warten zu lassen, bis N Threads eine Aktion abgeschlossen haben oder eine Aktion N-mal abgeschlossen wurde.Wenn die aktuelle Anzahl Null ist, kehrt diese Methode sofort zurück.
Wenn die aktuelle Anzahl größer als Null ist, wird sie dekrementiert. Wenn die neue Anzahl Null ist, werden alle wartenden Threads für Thread-Planungszwecke wieder aktiviert.
Erklärung Ihres Beispiels.
Sie haben die Anzahl für die
latch
Variable auf 3 gesetztSie haben diese Freigabe
latch
an den Worker-Thread übergeben:Processor
Runnable
Instanzen vonProcessor
wurden eingereichtExecutorService
executor
Der Haupt-Thread (
App
) wartet darauf, dass die Anzahl mit der folgenden Anweisung Null wirdProcessor
Der Thread schläft 3 Sekunden lang und verringert dann den Zählwert mitlatch.countDown()
Die erste
Process
Instanz ändert die Anzahl der Latches nach Abschluss aufgrund vonlatch.countDown()
.Die zweite
Process
Instanz ändert die Anzahl der Latches nach Abschluss aufgrund von 1latch.countDown()
.Die dritte
Process
Instanz ändert die Anzahl der Latches nach Abschluss aufgrund von auf 0latch.countDown()
.Die Nullzählung bei der Verriegelung bewirkt
App
, dass der Hauptfaden herauskommtawait
Das App-Programm druckt diese Ausgabe jetzt:
Completed
quelle
Dieses Beispiel aus Java Doc hat mir geholfen, die Konzepte klar zu verstehen:
Visuelle Interpretation:
Offensichtlich
CountDownLatch
kann ein Thread (hierDriver
) warten, bis eine Reihe laufender Threads (hierWorker
) mit ihrer Ausführung fertig sind.quelle
Wie in JavaDoc ( https://docs.oracle.com/javase/7/docs/api/java/util/concurrent/CountDownLatch.html ) erwähnt, ist CountDownLatch eine in Java 5 eingeführte Synchronisationshilfe. Hier erfolgt die Synchronisation nicht bedeutet, den Zugang zu einem kritischen Abschnitt einzuschränken. Sondern Sequenzierung von Aktionen verschiedener Threads. Die Art der Synchronisation, die durch CountDownLatch erreicht wird, ähnelt der von Join. Angenommen, es gibt einen Thread "M", der warten muss, bis andere Arbeitsthreads "T1", "T2", "T3" seine Aufgaben erledigt haben. Vor Java 1.5 kann dies folgendermaßen ausgeführt werden: M führt den folgenden Code aus
Der obige Code stellt sicher, dass Thread M seine Arbeit wieder aufnimmt, nachdem T1, T2, T3 seine Arbeit abgeschlossen haben. T1, T2, T3 können ihre Arbeit in beliebiger Reihenfolge erledigen. Dasselbe kann durch CountDownLatch erreicht werden, wobei T1, T2, T3 und Thread M dasselbe CountDownLatch-Objekt verwenden.
"M" -Anfragen:
countDownLatch.await();
wo wie "T1", "T2", "T3"
countDownLatch.countdown();
Ein Nachteil bei der Join-Methode ist, dass M über T1, T2, T3 Bescheid wissen muss. Wenn später ein neuer Arbeitsthread T4 hinzugefügt wird, muss sich auch M dessen bewusst sein. Dies kann mit CountDownLatch vermieden werden. Nach der Implementierung wäre die Aktionssequenz [T1, T2, T3] (die Reihenfolge von T1, T2, T3 könnte sowieso sein) -> [M]
quelle
Bestes Echtzeitbeispiel für countDownLatch in diesem Link CountDownLatchExample
quelle
quelle