Question

Y a-t-il un avantage à utiliser

java.util.concurrent .CountdownLatch

au lieu de

java.util.concurrent .Sémaphore ?

Pour autant que je sache, les fragments suivants sont presque équivalents:

1. Sémaphore

final Semaphore sem = new Semaphore(0);
for (int i = 0; i < num_threads; ++ i)
{
  Thread t = new Thread() {
    public void run()
    {
      try
      {
        doStuff();
      }
      finally
      {
        sem.release();
      }
    }
  };
  t.start();
}

sem.acquire(num_threads);

2: CountDownLatch

final CountDownLatch latch = new CountDownLatch(num_threads);
for (int i = 0; i < num_threads; ++ i)
{
  Thread t = new Thread() {
    public void run()
    {
      try
      {
        doStuff();
      }
      finally
      {
        latch.countDown();
      }
    }
  };
  t.start();
}

latch.await();

Sauf que dans le cas n ° 2, le verrou ne peut pas être réutilisé et, plus important encore, vous devez savoir à l'avance combien de threads seront créés (ou attendre qu'ils aient tous été démarrés avant de créer le verrou.)

Dans quelle situation le verrou pourrait-il être préférable?

Était-ce utile?

La solution

Le loquet à compte à rebours est fréquemment utilisé pour l'exact opposé de votre exemple. En règle générale, de nombreux threads se bloquent sur & wait; wait () " cela commencerait tous simultanément lorsque le décompte atteindrait zéro.

final CountDownLatch countdown = new CountDownLatch(1);
for (int i = 0; i < 10; ++ i){
   Thread racecar = new Thread() {    
      public void run()    {
         countdown.await(); //all threads waiting
         System.out.println("Vroom!");
      }
   };
   racecar.start();
}
System.out.println("Go");
countdown.countDown();   //all threads start now!

Vous pouvez également l'utiliser comme une "barrière" de style MPI. Cela force tous les threads à attendre que les autres threads rattrapent un certain point avant de continuer.

final CountDownLatch countdown = new CountDownLatch(num_thread);
for (int i = 0; i < num_thread; ++ i){
   Thread t= new Thread() {    
      public void run()    {
         doSomething();
         countdown.countDown();
         System.out.printf("Waiting on %d other threads.",countdown.getCount());
         countdown.await();     //waits until everyone reaches this point
         finish();
      }
   };
   t.start();
}

Cela dit, le loquet CountDown peut être utilisé en toute sécurité de la manière que vous avez montrée dans votre exemple.

Autres conseils

CountDownLatch est utilisé pour démarrez une série de threads et attendez qu'ils soient tous terminés (ou qu'ils appellent countDown () un nombre de fois donné.

Le sémaphore permet de contrôler le nombre de threads simultanés utilisant une ressource. Cette ressource peut être quelque chose comme un fichier, ou peut être le cpu en limitant le nombre de threads en cours d'exécution. Le compte sur un sémaphore peut monter et descendre à mesure que différents threads appellent acquérir () et release () .

Dans votre exemple, vous utilisez essentiellement Semaphore comme une sorte de compte UP . Étant donné que votre intention est d’attendre la fin de tous les threads, utilisez CountdownLatch pour clarifier votre intention.

Résumé court:

  1. Sémaphore et CountDownLatch a des objectifs différents.

  2. Utilisez Sémaphore pour contrôler l'accès des threads aux ressources.

  3. Utilisez CountDownLatch pour attendre la fin de tous les threads

Définition du sémaphore à partir de javadocs:

  

Un sémaphore conserve un ensemble de permis. Chaque acquérir () bloque si nécessaire jusqu'à ce qu'un permis soit disponible, puis le prend. Chaque release () ajoute un permis, libérant éventuellement un acquéreur bloquant.

Cependant, aucun objet d'autorisation réel n'est utilisé; le sémaphore conserve simplement un compte du nombre disponible et agit en conséquence.

Comment ça marche?

Les

sémaphores sont utilisés pour contrôler le nombre de threads simultanés utilisant une ressource. Cette ressource peut ressembler à une donnée partagée ou à un bloc de code ( section critique ) ou à n’importe quel fichier.

Le nombre sur un sémaphore peut monter et descendre à mesure que différents threads appellent acquérir () et release (). Mais à tout moment, vous ne pouvez pas avoir plus de threads que le nombre de sémaphores.

Cas d'utilisation de sémaphore:

  1. Limiter l’accès simultané au disque (cela peut nuire aux performances en raison de le disque concurrent cherche)
  2. Limitation de la création de threads
  3. Regroupement / limitation de connexion JDBC
  4. Limitation de la connexion réseau
  5. Limitation du processeur ou des tâches gourmandes en mémoire

Consultez cet article pour le sémaphore. utilise.

CountDownLatch définition de javadocs:

  

Aide à la synchronisation permettant à un ou plusieurs threads d'attendre la fin d'un ensemble d'opérations effectuées dans d'autres threads.

Comment ça marche?

CountDownLatch fonctionne avec un compteur initialisé avec le nombre de threads, qui est décrémenté chaque fois qu'un thread termine son exécution. Lorsque le nombre atteint zéro, cela signifie que tous les threads ont terminé leur exécution et que les threads en attente de verrouillage reprennent l'exécution.

Cas d'utilisation de CountDownLatch:

  1. Obtenir le maximum de parallélisme: Parfois, nous voulons commencer un certain nombre de threads en même temps pour obtenir un parallélisme maximal
  2. Attendez que N threads soient terminés avant de lancer l'exécution
  3. Détection des interblocages.

Consultez ce article pour bien comprendre les concepts de CountDownLatch.

Consultez le Pool de jointure de la fourche sur cet article aussi . Il présente certaines similitudes avec CountDownLatch .

Dites que vous êtes entré dans la boutique du golf professionnel, dans l’espoir de trouver un quatuor,

Lorsque vous faites la queue pour obtenir l'heure de départ d'un des agents de magasin professionnels, vous appelez essentiellement proshopVendorSemaphore.acquire () , une fois que vous obtenez l'heure de départ, vous appelez proshopVendorSemaphore. .release () .Remarque: l'un des opérateurs gratuits peut vous servir, c'est-à-dire une ressource partagée.

Maintenant vous arrivez au démarreur, il commence un CountDownLatch (4) et appelle wait () pour attendre les autres, pour votre partie que vous avez appelée "archivée" CountDownLatch . countDown () et le reste du plan à quatre. Lorsque tout arrive, le démarreur donne l’avance ( wait () l’appel revient)

Maintenant, après neuf trous lorsque chacun de vous prend une pause, supposons de nouveau que le démarreur commence, il utilise un 'nouveau' CountDownLatch (4) pour lancer le trou 10, même attente / sync que Trou 1.

Cependant, si le démarreur utilisait un CyclicBarrier pour commencer, il aurait pu réinitialiser la même instance dans le trou 10 au lieu d'un second verrou, qui utilise & amp; lancer.

En regardant la source librement disponible, il n’ya pas de magie dans la mise en oeuvre des deux classes, leur performance devrait donc être sensiblement la même. Choisissez celui qui rend votre intention plus évidente.

CountdownLatch fait en sorte que les threads attendent la méthode wait () jusqu'à ce que le décompte atteigne zéro. Alors peut-être que vous voulez que tous vos threads attendent jusqu'à 3 invocations de quelque chose, alors tous les threads peuvent disparaître. Un verrou ne peut généralement pas être réinitialisé.

Un sémaphore permet aux threads de récupérer des permis, ce qui empêche un trop grand nombre de threads de s’exécuter en même temps. Il bloque s’il ne parvient pas à obtenir le (s) permis (s) requis (s). Les permis peuvent être renvoyés à un sémaphore permettant aux autres threads en attente de continuer.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top