Quelqu'un peut-il m'aider à comprendre ce que Java CountDownLatch
et quand l'utiliser?
Je n'ai pas une idée très claire du fonctionnement de ce programme. Si je comprends bien, les trois threads commencent à la fois et chaque thread appellera CountDownLatch après 3000 ms. Le compte à rebours diminuera donc un par un. Une fois que le verrou est à zéro, le programme imprime "Terminé". Peut-être que la façon dont j'ai compris est incorrecte.
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.");
}
}
Réponses:
Oui, vous avez bien compris.
CountDownLatch
fonctionne selon le principe du verrouillage, le filetage principal attendra que la porte soit ouverte. Un thread attend n threads, spécifié lors de la création duCountDownLatch
.Tout thread, généralement le thread principal de l'application, qui appelle
CountDownLatch.await()
attendra que le nombre atteigne zéro ou qu'il soit interrompu par un autre thread. Tous les autres threads doivent compter à rebours en appelantCountDownLatch.countDown()
une fois qu'ils sont terminés ou prêts.Dès que count atteint zéro, le thread en attente continue. L'un des inconvénients / avantages de
CountDownLatch
est qu'il n'est pas réutilisable: une fois que le nombre atteint zéro, vous ne pouvez pas utiliserCountDownLatch
.Éditer:
Utilisation
CountDownLatch
lorsqu'un thread (comme le thread principal) doit attendre qu'un ou plusieurs threads se terminent, avant de pouvoir continuer le traitement.Un exemple classique d'utilisation
CountDownLatch
en Java est une application Java principale côté serveur qui utilise une architecture de services, dans laquelle plusieurs services sont fournis par plusieurs threads et l'application ne peut pas démarrer le traitement tant que tous les services n'ont pas démarré avec succès.La question de PS OP a un exemple assez simple, je n'en ai donc pas inclus.
la source
One thread waits for n number of threads specified while creating CountDownLatch in Java
. Si vous avez besoin d'un tel mécanisme, il est prudent de l'utiliserCyclicBarrier
. La différence conceptuelle fondamentale entre ces deux, comme indiqué dansJava concurrency in Practice
est:Latches are for waiting for events; barriers are for waiting for other threads
.cyclicBarrier.await()
passe dans un état de blocage.CountDownLatch
en Java est un type de synchroniseur qui permetThread
d'attendre un ou plusieursThread
s avant de commencer le traitement.CountDownLatch
fonctionne sur le principe du verrou, le fil attendra que la porte soit ouverte. Un thread attend len
nombre de threads spécifié lors de la créationCountDownLatch
.par exemple
final CountDownLatch latch = new CountDownLatch(3);
Ici, nous mettons le compteur à 3.
Tout thread, généralement le thread principal de l'application, qui appelle
CountDownLatch.await()
attendra que le nombre atteigne zéro ou qu'il soit interrompu par un autreThread
. Tous les autres threads doivent effectuer un compte à rebours en appelantCountDownLatch.countDown()
une fois qu'ils sont terminés ou prêts à travailler. dès que le compte atteint zéro, leThread
attente commence à fonctionner.Ici, le compte est décrémenté de
CountDownLatch.countDown()
méthode.Le
Thread
qui appelle leawait()
méthode attendra que le décompte initial atteigne zéro.Pour rendre le compte nul, les autres threads doivent appeler la
countDown()
méthode. Une fois que le compte est devenu zéro, le thread qui a invoqué leawait()
méthode reprend (démarre son exécution).L'inconvénient de
CountDownLatch
est qu'il n'est pas réutilisable: une fois que le compte devient nul, il n'est plus utilisable.la source
new CountDownLatch(3)
comme nous avons 3 threads dunewFixedThreadPool
défini?NikolaB l'a très bien expliqué, cependant un exemple serait utile à comprendre, voici donc un exemple simple ...
la source
Il est utilisé lorsque nous voulons attendre plus d'un thread pour terminer sa tâche. C'est similaire à rejoindre des threads.
Où nous pouvons utiliser CountDownLatch
Considérez un scénario où nous avons une exigence où nous avons trois threads "A", "B" et "C" et nous voulons démarrer le thread "C" uniquement lorsque les threads "A" et "B" terminent ou achèvent partiellement leur tâche.
Il peut être appliqué à un scénario informatique réel
Imaginez un scénario dans lequel le responsable a divisé les modules entre les équipes de développement (A et B) et il souhaite les attribuer à l'équipe d'assurance qualité pour des tests uniquement lorsque les deux équipes ont terminé leur tâche.
La sortie du code ci-dessus sera:
Tâche confiée à l'équipe de développement devB
Tâche confiée à l'équipe de développement devA
Tâche terminée par l'équipe de développement devB
Tâche terminée par l'équipe de développement devA
Tâche assignée à l'équipe QA
Tâche terminée par l'équipe QA
Ici Attendre les () méthode attend drapeau CountDownLatch à devenir 0 et Countdown () méthode décrémente drapeau CountDownLatch par 1.
Limitation de JOIN: L' exemple ci-dessus peut également être réalisé avec JOIN, mais JOIN ne peut pas être utilisé dans deux scénarios:
la source
CoundDownLatch vous permet de faire attendre un thread jusqu'à ce que tous les autres threads aient terminé leur exécution.
Le pseudo code peut être:
la source
Un bon exemple d'utilisation de quelque chose comme celui-ci est avec Java Simple Serial Connector, qui accède aux ports série. En règle générale, vous allez écrire quelque chose sur le port, et de manière asyncronale, sur un autre thread, le périphérique répondra sur un SerialPortEventListener. En règle générale, vous souhaiterez faire une pause après avoir écrit sur le port pour attendre la réponse. La gestion manuelle des verrous de thread pour ce scénario est extrêmement délicate, mais l'utilisation de Countdownlatch est facile. Avant de penser que vous pouvez le faire autrement, faites attention aux conditions de course auxquelles vous n'avez jamais pensé !!
Pseudocode:
la source
Si vous ajoutez du débogage après votre appel à latch.countDown (), cela peut vous aider à mieux comprendre son comportement.
La sortie affichera le décompte en cours de décrémentation. Ce «compte» est en fait le nombre de tâches exécutables (objets Processeur) que vous avez démarrées contre lesquelles countDown () n'a pas été invoqué et est donc bloqué le thread principal lors de son appel à latch.await ().
la source
À partir de la documentation d'Oracle sur CountDownLatch :
A
CountDownLatch
est initialisé avec un décompte donné. Lesawait
méthodes se bloquent jusqu'à ce que le nombre actuel atteigne zéro en raison des appels de lacountDown()
méthode, après quoi tous les threads en attente sont libérés et toutes les invocations ultérieures de wait sont immédiatement renvoyées. Il s'agit d'un phénomène ponctuel - le décompte ne peut pas être réinitialisé.Un
CountDownLatch
initialisé avec un compte de un sert de simple verrou marche / arrêt, ou porte: tous les threads invoquant attendent attendre à la porte jusqu'à ce qu'il soit ouvert par un thread invoquant countDown ().Un
CountDownLatch
initialisé à N peut être utilisé pour faire attendre un thread jusqu'à ce que N threads aient terminé une action ou qu'une action ait été effectuée N fois.Si le décompte actuel est zéro, cette méthode retourne immédiatement.
Si le décompte actuel est supérieur à zéro, il est décrémenté. Si le nouveau nombre est égal à zéro, tous les threads en attente sont réactivés à des fins de planification de thread.
Explication de votre exemple.
Vous avez défini le compte à 3 pour la
latch
variableVous avez transmis ce partage
latch
au fil de discussion Worker:Processor
Runnable
instances deProcessor
ont été soumises àExecutorService
executor
Le thread principal (
App
) attend que le nombre devienne zéro avec l'instruction ci-dessousProcessor
thread dort pendant 3 secondes, puis décrémente la valeur de comptage aveclatch.countDown()
La première
Process
instance changera le nombre de verrous à 2 après son achèvement en raison delatch.countDown()
.La deuxième
Process
instance changera le nombre de verrous à 1 après son achèvement en raison delatch.countDown()
.Troisième
Process
instance changera le nombre de verrous à 0 après son achèvement en raison delatch.countDown()
.Le comptage nul sur le verrou provoque le filetage principal
App
sortir leawait
Le programme d'application imprime cette sortie maintenant:
Completed
la source
Cet exemple de Java Doc m'a aidé à comprendre clairement les concepts:
Interprétation visuelle:
Evidemment,
CountDownLatch
permet à un thread (iciDriver
) d'attendre jusqu'à ce qu'un tas de threads en cours (iciWorker
) aient terminé leur exécution.la source
Comme mentionné dans JavaDoc ( https://docs.oracle.com/javase/7/docs/api/java/util/concurrent/CountDownLatch.html ), CountDownLatch est une aide à la synchronisation, introduite dans Java 5. Ici, la synchronisation ne fonctionne pas signifie restreindre l'accès à une section critique. Mais plutôt séquencer les actions de différents threads. Le type de synchronisation obtenu via CountDownLatch est similaire à celui de Join. Supposons qu'il existe un thread "M" qui doit attendre que d'autres threads de travail "T1", "T2", "T3" terminent ses tâches Avant Java 1.5, la façon dont cela peut être fait est, M exécutant le code suivant
Le code ci-dessus garantit que le thread M reprend son travail après que T1, T2, T3 ait terminé son travail. T1, T2, T3 peuvent terminer leurs travaux dans n'importe quel ordre. La même chose peut être obtenue via CountDownLatch, où T1, T2, T3 et thread M partagent le même objet CountDownLatch.
Requêtes "M":
countDownLatch.await();
où comme "T1", "T2", "T3" fait
countDownLatch.countdown();
Un inconvénient de la méthode de jointure est que M doit connaître T1, T2, T3. Si un nouveau thread de travail T4 est ajouté ultérieurement, M doit également en être conscient. Cela peut être évité avec CountDownLatch. Après la mise en œuvre, la séquence d'action serait [T1, T2, T3] (l'ordre de T1, T2, T3 pourrait être de toute façon) -> [M]
la source
Meilleur exemple en temps réel pour countDownLatch expliqué dans ce lien CountDownLatchExample
la source
la source