其他实用程序不太常见,因此有时它们可能会使我们逃脱,但是请记住它们是很好的。 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