Java并发教程– CountDownLatch

Java中的某些并发实用程序自然会比其他并发实用程序受到更多关注,因为它们可以解决通用问题而不是更具体的问题。 我们大多数人经常遇到执行程序服务和并发集合之类的事情。

其他实用程序不太常见,因此有时它们可​​能会使我们逃脱,但是请记住它们是很好的。 CountDownLatch是这些工具之一。

CountDownLatch –更通用的等待/通知机制

各种Java开发人员都应该熟悉等待/通知方法,直到达到条件为止。 以下是有关其工作原理的一些示例:

public void testWaitNotify() throws Exception {
   final Object mutex = new Object();
   Thread t = new Thread() {
      public void run() {
      // we must acquire the lock before waiting to be notified
      synchronized(mutex) {
         System.out.println("Going to wait " +
                            "(lock held by " + Thread.currentThread().getName() + ")");
            try {
               mutex.wait(); // this will release the lock to be notified (optional timeout can be supplied)
            } catch (InterruptedException e) {
               e.printStackTrace();
            } 

            System.out.println("Done waiting " +
                               "(lock held by " + Thread.currentThread().getName() + ")");
         }
      }
   };

   t.start(); // start her up and let her wait()

   // not normally how we do things, but good enough for demonstration purposes
   Thread.sleep(1000);

   // we acquire the lock released by wait(), and notify()
   synchronized (mutex) {
      System.out.println("Going to notify " +
                         "(lock held by " + Thread.currentThread().getName() + ")");
      mutex.notify();
      System.out.println("Done notify " +
                         "(lock held by " + Thread.currentThread().getName() + ")");
   }

}

输出量

Going to wait (lock held by Thread-0)
Going to notify (lock held by main)
Done notify (lock held by main)
Done waiting (lock held by Thread-0)

实际上, CountDownLatch可以类似于等待/通知,仅使用一个通知即可使用-也就是说,只要您不希望在获取锁并调用wait()之前调用notify()时, wait()就会停顿。 。 因此,它实际上是更宽容的,在某些情况下,这正是您想要的。 这是一个示例:

public void testWaitNotify() throws Exception {
   final CountDownLatch latch = new CountDownLatch(1); // just one time
   Thread t = new Thread() {
      public void run() {
         // no lock to acquire!
         System.out.println("Going to count down...");
         latch.countDown();
      }
   };

   t.start(); // start her up and let her wait()
   System.out.println("Going to await...");
   latch.await();
   System.out.println("Done waiting!");
}

如您所见,它比等待/通知更简单,并且所需的代码更少。 它还允许我们在调用wait()之前调用最终释放该块的条件。 这可能意味着代码更安全。

真实的例子

因此我们知道我们可以将其用作更简单的等待/通知机制,但是您可能已经在上面看到了构造函数参数。 在构造函数中,指定解锁之前需要递减锁存器的次数。 有什么可能的用途? 好吧,它可以使进程等待直到采取了一定数量的动作。

例如,如果您具有可以通过侦听器或类似方法挂接到的异步进程,则可以创建单元测试以验证是否进行了一定数量的调用。 这使我们只需要在正常情况下需要的时间(或在保释并假设失败之前的某个限制)即可。

最近,我遇到了一种情况,我必须验证是否已将JMS消息从队列中拉出并正确处理。 这自然是异步的,并且不在我的控制范围之内,并且也不选择模拟,因为它是具有Spring上下文的完全组装的应用程序,等等。为了测试这一点,我对使用服务进行了微小的更改,以允许在邮件已处理。 然后,我可以临时添加一个侦听器,该侦听器使用CountDownLatch保持测试尽可能接近同步。

这是显示概念的示例:

public void testSomeProcessing() throws Exception {
   // should be called twice
   final CountDownLatch testLatch = new CountDownLatch(2);
   ExecutorService executor = Executors.newFixedThreadPool(1);
   AsyncProcessor processor = new AsyncProcessor(new Observer() {
      // this observer would be the analogue for a listener in your async process
      public void update(Observable o, Object arg) {
         System.out.println("Counting down...");
         testLatch.countDown();
      }
   });

   //submit two tasks to be process
   // (in my real world example, these were JMS messages)
   executor.submit(processor);
   executor.submit(processor);

   System.out.println("Submitted tasks. Time to wait...");
   long time = System.currentTimeMillis();
   testLatch.await(5000, TimeUnit.MILLISECONDS); // bail after a reasonable time
   long totalTime = System.currentTimeMillis() - time;

   System.out.println("I awaited for " + totalTime +
                      "ms. Did latch count down? " + (testLatch.getCount() == 0));

   executor.shutdown();
}

// just a process that takes a random amount of time
// (up to 2 seconds) and calls its listener
public class AsyncProcessor implements Callable<Object> {
      private Observer listener;
      private AsyncProcessor(Observer listener) {
      this.listener = listener;
   }

   public Object call() throws Exception {
      // some processing here which can take all kinds of time...
      int sleepTime = new Random().nextInt(2000);
      System.out.println("Sleeping for " + sleepTime + "ms");
      Thread.sleep(sleepTime);
      listener.update(null, null); // not standard usage, but good for a demo
      return null;
   }
}

输出量

Submitted tasks. Time to wait...
Sleeping for 739ms
Counting down...
Sleeping for 1742ms
Counting down...
I awaited for 2481ms. Did latch count down? true

结论

CountDownLatch就是这样。 它不是一个复杂的主题,而且用途有限,但是当您遇到类似我的问题时,很高兴看到示例并知道它们在您的工具箱中。 将来,如果没有其他问题,我一定会牢记这一点,以便进行更简单的等待/通知。 如果您对此帖子或系列中的其他帖子有疑问或评论,请留言。

参考:来自Carfey Software博客的 JCG合作伙伴Java并发第6部分– CountDownLatch

相关文章 :

翻译自: https://www.javacodegeeks.com/2011/09/java-concurrency-tutorial.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值