简体   繁体   English

CountDownLatch 与信号量

[英]CountDownLatch vs. Semaphore

Is there any advantage of using使用有什么好处吗

java.util.concurrent.CountdownLatch java.util.concurrent.CountdownLatch

instead of代替

java.util.concurrent.Semaphore ? java.util.concurrent.Semaphore

As far as I can tell the following fragments are almost equivalent:据我所知,以下片段几乎是等效的:

1. Semaphore 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: CountDownLatch 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();

Except that in case #2 the latch cannot be reused and more importantly you need to know in advance how many threads will be created (or wait until they are all started before creating the latch.)除了在 #2 的情况下,闩锁不能被重用,更重要的是,您需要提前知道将创建多少线程(或等到它们全部启动后再创建闩锁。)

So in what situation might the latch be preferable?那么在什么情况下闩锁更可取呢?

CountDownLatch is frequently used for the exact opposite of your example. CountDownLatch经常用于与您的示例完全相反的情况。 Generally, you would have many threads blocking on await() that would all start simultaneously when the countown reached zero.通常,您会在await()上阻塞许多线程,当计数达到零时,它们都会同时启动。

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!

You could also use this as an MPI-style "barrier" that causes all threads to wait for other threads to catch up to a certain point before proceeding.您还可以将其用作 MPI 样式的“屏障”,使所有线程在继续之前等待其他线程赶上某个点。

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();
}

That all said, the CountDownLatch can safely be used in the manner you've shown in your example.尽管如此, CountDownLatch可以按照您在示例中显示的方式安全地使用。

CountDownLatch is used to start a series of threads and then wait until all of them are complete (or until they call countDown() a given number of times. CountDownLatch用于启动一系列线程,然后等待所有线程完成(或直到它们调用countDown()给定次数。

Semaphore is used to control the number of concurrent threads that are using a resource.信号量用于控制使用资源的并发线程数。 That resource can be something like a file, or could be the cpu by limiting the number of threads executing.该资源可以是文件之类的东西,也可以是限制执行线程数的 cpu。 The count on a Semaphore can go up and down as different threads call acquire() and release() .当不同的线程调用acquire()release()时,信号量的计数可以上下波动。

In your example, you're essentially using Semaphore as a sort of Count UP Latch.在您的示例中,您本质上是将信号量用作一种 Count UP Latch。 Given that your intent is to wait on all threads finishing, using the CountdownLatch makes your intention clearer.鉴于您的意图是等待所有线程完成,使用CountdownLatch会使您的意图更加清晰。

Short summary:简短的摘要:

  1. Semaphore and CountDownLatch serves different purpose. SemaphoreCountDownLatch用于不同的目的。

  2. Use Semaphore to control thread access to resource.使用Semaphore来控制线程对资源的访问。

  3. Use CountDownLatch to wait for completion of all threads使用CountDownLatch等待所有线程完成

Semaphore definition from Javadocs: Javadocs 中的Semaphore定义:

A Semaphore maintains a set of permits. Semaphore维护一组许可。 Each acquire() blocks if necessary until a permit is available, and then takes it.如有必要,每个acquire()阻塞,直到获得许可为止,然后获取它。 Each release() adds a permit, potentially releasing a blocking acquirer.每个release()添加一个许可,可能会释放一个阻塞的获取者。

However, no actual permit objects are used;但是,没有使用实际的许可对象; the Semaphore just keeps a count of the number available and acts accordingly. Semaphore只是计算可用的数量并相应地采取行动。

How does it work?它是如何工作的?

Semaphores are used to control the number of concurrent threads that are using a resource.That resource can be something like a shared data, or a block of code ( critical section ) or any file.信号量用于控制使用资源的并发线程数。资源可以是共享数据、代码块(临界区)或任何文件。

The count on a Semaphore can go up and down as different threads call acquire() and release() .当不同的线程调用acquire()release()时, Semaphore的计数可以上下波动。 But at any point of time, you can't have more number of threads greater than Semaphore count.但是在任何时候,线程数都不能超过信号量计数。

Semaphore Use cases: Semaphore用例:

  1. Limiting concurrent access to disk (as performance degrades due to competing disk seeks)限制对磁盘的并发访问(由于竞争磁盘寻道导致性能下降)
  2. Thread creation limiting线程创建限制
  3. JDBC connection pooling / limiting JDBC 连接池/限制
  4. Network connection throttling网络连接限制
  5. Throttling CPU or memory intensive tasks限制 CPU 或内存密集型任务

Have a look at this article for semaphore uses.看看这篇文章,了解信号量的使用。

CountDownLatch definition from Javadocs:来自 Javadocs 的CountDownLatch定义:

A synchronization aid that allows one or more threads to wait until a set of operations being performed in other threads completes.一种同步辅助,允许一个或多个线程等待,直到在其他线程中执行的一组操作完成。

How does it work?它是如何工作的?

CountDownLatch works by having a counter initialized with number of threads, which is decremented each time a thread complete its execution. CountDownLatch工作原理是使用线程数初始化计数器,每次线程完成执行时该计数器都会递减。 When count reaches to zero, it means all threads have completed their execution, and thread waiting on latch resume the execution.当计数为零时,表示所有线程都已完成执行,等待闩锁的线程继续执行。

CountDownLatch Use cases: CountDownLatch用例:

  1. Achieving Maximum Parallelism: Sometimes we want to start a number of threads at the same time to achieve maximum parallelism Achieving Maximum Parallelism:有时我们想同时启动多个线程来实现最大并行度
  2. Wait N threads to completes before start execution在开始执行之前等待 N 个线程完成
  3. Deadlock detection.死锁检测。

Have a look at this article to understand CountDownLatch concepts clearly.看看这篇文章可以清楚地理解CountDownLatch概念。

Have a look at Fork Join Pool at this article too.也可以在这篇文章中查看Fork Join Pool It has some similarities to CountDownLatch .它与CountDownLatch有一些相似之处。

Say you walked in to golf pro shop, hoping to find a foursome,假设你走进高尔夫专卖店,希望找到一个四人组,

When you stand in line to get a tee time from one of the pro shop attendants, essentially you called proshopVendorSemaphore.acquire() , once you get a tee time, you called proshopVendorSemaphore.release() .Note: any of the free attendants can service you, ie shared resource.当您排队从一位专业商店服务员那里获得开球时间时,本质上您调用了proshopVendorSemaphore.acquire() ,一旦您获得开球时间,您就会调用proshopVendorSemaphore.release() 。注意:任何免费服务员都可以为您服务,即共享资源。

Now you walk up to starter, he starts a CountDownLatch(4) and calls await() to wait for others, for your part you called checked-in ie CountDownLatch .现在你走到 starter,他启动一个CountDownLatch(4)并调用await()等待其他人,对于你来说,你调用了 check-in ,即CountDownLatch countDown() and so does rest of the foursome. countDown()等四人组的其余部分也是如此。 When all arrive, starter gives go ahead( await() call returns)全部到达后,starter 继续执行( await()调用返回)

Now, after nine holes when each of you take a break, hypothetically lets involve starter again, he uses a 'new' CountDownLatch(4) to tee off Hole 10, same wait/sync as Hole 1.现在,在九个洞之后,当你们每个人都休息时,假设让首发球员再次参与,他使用“新的” CountDownLatch(4)在第 10 洞开球,与第 1 洞相同的等待/同步。

However, if the starter used a CyclicBarrier to begin with, he could have reset the same instance in Hole 10 instead of a second latch, which use & throw.但是,如果起始者使用CyclicBarrier开始,他可以在第 10 洞重置相同的实例,而不是使用 & throw 的第二个闩锁。

Looking at the freely available source, there is no magic in the implementation of the two classes, so their performance should be much the same.查看免费提供的源代码,这两个类的实现没有什么神奇之处,因此它们的性能应该大同小异。 Choose the one that makes your intent more obvious.选择使您的意图更加明显的一种。

CountdownLatch makes threads wait on the await() method, until such a time as the count has reached zero. CountdownLatch使线程等待await()方法,直到计数达到零。 So maybe you want all your threads to wait until 3 invocations of something, then all the threads can go.因此,也许您希望所有线程都等待 3 次调用某事,然后所有线程都可以运行。 A Latch generally can not be reset. A Latch一般不能复位。

A Semaphore allows threads to retrieve permits, which prevents too many threads from executing at once, blocking if it cannot get the permit(s) it requires to proceed. Semaphore允许线程检索许可,这可以防止过多的线程同时执行,如果无法获得继续执行所需的许可就会阻塞。 Permits can be returned to a Semaphore allowing the other waiting threads to proceed.许可可以返回给Semaphore允许其他等待的线程继续进行。

Semaphore controls access to a shared resource through the use of a counter.信号量通过使用计数器来控制对共享资源的访问。 If the counter is greater than zero, then access is allowed.如果计数器大于零,则允许访问。 If it is zero, then access is denied.如果为零,则拒绝访问。 Counter is counting the permits that allow access to shared resource.计数器正在计算允许访问共享资源的许可。 Thus to access the resource, a thread must be granted a permit from the semaphore.因此,要访问资源,必须从信号量中授予线程许可。

CountDownlatch make a thread to wait until one or more events have occured. CountDownlatch 使线程等待一个或多个事件发生。 A countDownLatch is initially created with a count of the number of events that much occur before the latch is released. countDownLatch 最初是用在闩锁释放之前发生的事件数量的计数创建的。 Each time an event happens, the count is decremented.每次发生事件时,计数都会递减。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM