207 votes

Comment le CountDownLatch est-il utilisé dans le multithreading Java ?

Quelqu'un peut-il m'aider à comprendre ce que Java CountDownLatch est 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 démarrent en même temps et chaque thread appelle CountDownLatch après 3000ms. Le compte à rebours sera donc décrémenté un par un. Une fois que le verrou est à zéro, le programme imprime "Completed". Peut-être 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.");
    }

}

218voto

NikolaB Points 2842

Oui, vous avez bien compris. CountDownLatch fonctionne selon le principe du verrou, le fil principal attendra que la porte soit ouverte. Un thread attend que n spécifié lors de la création de l CountDownLatch .

Tout thread, généralement le thread principal de l'application, qui appelle CountDownLatch.await() attendra jusqu'à ce que le compte atteigne zéro ou qu'il soit interrompu par un autre thread. Tous les autres threads doivent décompter en appelant CountDownLatch.countDown() une fois qu'ils sont terminés ou prêts.

Dès que le compte atteint zéro, le fil d'attente continue. L'un des inconvénients de CountDownLatch est qu'il n'est pas réutilisable : une fois que le compte atteint zéro, vous ne pouvez plus utiliser CountDownLatch plus.

Edit :

Utilice CountDownLatch lorsqu'un thread (comme le thread principal) doit attendre qu'un ou plusieurs threads se terminent, avant de pouvoir poursuivre le traitement.

Un exemple classique d'utilisation de CountDownLatch en Java est une application Java centrale côté serveur qui utilise une architecture de services, dans laquelle plusieurs services sont fournis par plusieurs threads et l'application ne peut pas commencer le traitement tant que tous les services n'ont pas démarré avec succès.

P.S. La question de l'OP a un exemple assez simple, donc je n'en ai pas inclus un.

44voto

Vishal Akkalkote Points 686

CountDownLatch en Java est un type de synchroniseur qui permet à un Thread pour attendre un ou plusieurs Thread avant de commencer le traitement.

CountDownLatch fonctionne sur le principe du verrou, le fil attendra que la porte soit ouverte. Un thread attend que n nombre de threads spécifié lors de la création CountDownLatch .

par exemple final CountDownLatch latch = new CountDownLatch(3);

Ici, nous mettons le compteur à 3.

Tout thread, habituellement le thread principal de l'application, qui appelle CountDownLatch.await() attendra jusqu'à ce que le compte atteigne zéro ou qu'il soit interrompu par une autre Thread . Tous les autres threads doivent effectuer un compte à rebours en appelant CountDownLatch.countDown() dès qu'elles sont terminées ou prêtes pour le travail. dès que le compte atteint zéro, le Thread L'attente commence à courir.

Ici, le compte est décrémenté par CountDownLatch.countDown() méthode.

El Thread qui appelle le await() attendra que le compte initial atteigne zéro.

Pour faire le compte à zéro, les autres threads doivent appeler la fonction countDown() méthode. Lorsque le compte devient nul, le thread qui a invoqué la méthode await() reprendra (commencera son exécution).

L'inconvénient de CountDownLatch est qu'il n'est pas réutilisable : une fois que le compte devient zéro, il n'est plus utilisable.

24voto

vikashait Points 499

NikolaB l'a très bien expliqué, Cependant un exemple serait utile pour comprendre, Voici donc un exemple simple...

 import java.util.concurrent.*;

  public class CountDownLatchExample {

  public static class ProcessThread implements Runnable {

    CountDownLatch latch;
    long workDuration;
    String name;

    public ProcessThread(String name, CountDownLatch latch, long duration){
        this.name= name;
        this.latch = latch;
        this.workDuration = duration;
    }

    public void run() {
        try {
            System.out.println(name +" Processing Something for "+ workDuration/1000 + " Seconds");
            Thread.sleep(workDuration);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(name+ "completed its works");
        //when task finished.. count down the latch count...

        // basically this is same as calling lock object notify(), and object here is latch
        latch.countDown();
    }
}

public static void main(String[] args) {
    // Parent thread creating a latch object
    CountDownLatch latch = new CountDownLatch(3);

    new Thread(new ProcessThread("Worker1",latch, 2000)).start(); // time in millis.. 2 secs
    new Thread(new ProcessThread("Worker2",latch, 6000)).start();//6 secs
    new Thread(new ProcessThread("Worker3",latch, 4000)).start();//4 secs

    System.out.println("waiting for Children processes to complete....");
    try {
        //current thread will get notified if all chidren's are done 
        // and thread will resume from wait() mode.
        latch.await();
    } catch (InterruptedException e) {
        e.printStackTrace();
    }

    System.out.println("All Process Completed....");

    System.out.println("Parent Thread Resuming work....");

     }
  }

24voto

V Jo Points 331

Il est utilisé lorsque l'on veut attendre que plus d'un thread termine sa tâche. Il est similaire à Join in threads.

Où nous pouvons utiliser CountDownLatch

Considérons 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" seulement quand les threads "A" et "B" ont terminé ou partiellement terminé leur tâche.

Il peut être appliqué à un scénario informatique réel

Considérons un scénario dans lequel le gestionnaire a divisé les modules entre les équipes de développement (A et B) et il veut les attribuer à l'équipe d'assurance qualité pour les tester uniquement lorsque les deux équipes ont terminé leur tâche.

public class Manager {
    public static void main(String[] args) throws InterruptedException {
        CountDownLatch countDownLatch = new CountDownLatch(2);
        MyDevTeam teamDevA = new MyDevTeam(countDownLatch, "devA");
        MyDevTeam teamDevB = new MyDevTeam(countDownLatch, "devB");
        teamDevA.start();
        teamDevB.start();
        countDownLatch.await();
        MyQATeam qa = new MyQATeam();
        qa.start();
    }   
}

class MyDevTeam extends Thread {   
    CountDownLatch countDownLatch;
    public MyDevTeam (CountDownLatch countDownLatch, String name) {
        super(name);
        this.countDownLatch = countDownLatch;       
    }   
    @Override
    public void run() {
        System.out.println("Task assigned to development team " + Thread.currentThread().getName());
        try {
                Thread.sleep(2000);
        } catch (InterruptedException ex) {
                ex.printStackTrace();
        }
        System.out.println("Task finished by development team " + Thread.currentThread().getName());
        this.countDownLatch.countDown();
    }
}

class MyQATeam extends Thread {   
    @Override
    public void run() {
        System.out.println("Task assigned to QA team");
        try {
            Thread.sleep(2000);
        } catch (InterruptedException ex) {
            ex.printStackTrace();
        }
        System.out.println("Task finished by QA team");
    }
}

La sortie du code ci-dessus sera :

Tâche assignée à l'équipe de développement devB

Tâche assigné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 AQ

Tâche terminée par l'équipe AQ

Aquí await() attend que l'indicateur countdownlatch devienne 0, et countDown() décrémente l'indicateur countdownlatch de 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 :

  1. Lorsque nous utilisons ExecutorService au lieu de la classe Thread pour créer des threads.
  2. Modifiez l'exemple ci-dessus où le responsable veut remettre le code à l'équipe d'assurance qualité dès que l'équipe de développement a terminé sa tâche à 80 %. Cela signifie que CountDownLatch nous permet de modifier l'implémentation qui peut être utilisée pour attendre un autre thread pour son exécution partielle.

4voto

CoundDownLatch vous permet de faire attendre un thread jusqu'à ce que tous les autres threads aient terminé leur exécution.

Le pseudo-code peut l'être :

// Main thread starts
// Create CountDownLatch for N threads
// Create and start N threads
// Main thread waits on latch
// N threads completes there tasks are returns
// Main thread resume execution

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X