104 votes

CountDownLatch vs. Semaphore

Est-il un avantage à l'utilisation de java.util.de façon concomitante.CountdownLatch au lieu de java.util.de façon concomitante.Sémaphore? Aussi loin que je peux dire fragments sont presque équivalents:

1:

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:

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 avez besoin de savoir à l'avance combien de threads sera créé (ou attendre jusqu'à ce qu'ils sont tout a commencé avant la création de l'loquet.)

Donc, en quoi la situation pourrait le loquet être préférable?

117voto

James Schek Points 11070

Le compte à rebours loquet est fréquemment utilisé pour l'exact opposé de votre exemple. En général, vous disposez de nombreux fils de blocage sur "await()" qui commencent tous à la fois lorsque le countown atteint 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 un MPI de style "barrière" qui provoque tous les threads pour attendre les autres threads pour attraper jusqu'à 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();
}

Que tout est dit, le compte à Rebours loquet peut en toute sécurité être utilisé de la manière dont vous avez fait preuve dans votre exemple.

72voto

mtruesdell Points 1639

CountdownLatch est utilisé pour lancer une série de fils et ensuite, attendre jusqu'à ce que tous d'entre eux sont complets (ou jusqu'à ce qu'ils appellent le compte à rebours() un nombre donné de fois.

Sémaphore est utilisé pour contrôler le nombre de threads simultanés qui sont l'utilisation d'une ressource. Cette ressource peut être quelque chose comme un fichier, ou peut être le cpu qui limite le nombre de threads en cours d'exécution. Le comte sur un Sémaphore peut aller en haut et en bas, comme les différents threads d'appel d'acquérir() et release().

Dans votre exemple, vous êtes essentiellement en utilisant un Sémaphore comme une sorte de Comte de*JUSQU'à*Loquet. Étant donné que votre intention est d'attendre sur tous les fils de finition, à l'aide de la CountdownLatch rend votre intention plus claire.

6voto

Raj Srinivas Points 11

Dire que vous êtes entré dans le golf pro shop, en espérant trouver un quatuor,

Quand vous êtes debout en ligne pour obtenir une heure de départ de l'un de la boutique du pro, les agents de bord, essentiellement, vous appelle proshopVendorSemaphore.acquire(), une fois que vous obtenez une heure de départ, vous avez appelé proshopVendorSemaphore.release().Note: tous les de la gratuit des standards de service vous, c'est à dire de la ressource partagée.

Maintenant, vous marchez jusqu'à starter, il commence une CountDownLatch(4) et les appels await() pour attendre les autres, pour votre part, vous l'avez appelé le check-in c'est à dire countDownLatch().compte à rebours, donc il ne reste du quatuor. Quand arrivent tous, le starter donne le feu vert(await() retours d'appel)

Maintenant, après neuf trous et chacun de vous de prendre une pause, à titre d'hypothèse permet d'impliquer starter de nouveau, il utilise un "nouveau" CountDownLatch(4) au départ de Trou de 10, de même attendre/sync comme le Trou n ° 1.

Toutefois, si le démarreur utilisé cyclique de la barrière pour commencer, il aurait pu réinitialiser la même instance dans le Trou du 10 au lieu d'un deuxième verrou, l'utilisation et la jeter.

1voto

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

0voto

Spencer Kormos Points 3082

CountdownLatch fait threads attendent le attendent() la méthode, jusqu'à ce que le comte a atteint zéro. Alors peut-être que vous souhaitez que tous les threads d'attendre jusqu'à 3 invocations de quelque chose, alors tous les threads peuvent aller. Un Loquet ne peuvent généralement pas être réinitialisé.

Un Sémaphore permet aux threads pour récupérer le permet, ce qui empêche trop de threads de s'exécuter à la fois, de blocage si elle ne peut pas obtenir le permis(s) elle nécessite de procéder. Les permis peuvent être retournés pour un Sémaphore de permettre aux autres threads en attente de procéder.

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