其他實用程序不太常見,因此有時它們可??能會使我們逃脫,但是請記住它們是很好的。 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 notifiedsynchronized(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 purposesThread.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 timeThread 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 twicefinal 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 processpublic 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 timelong 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 demoreturn 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 。
- Java并發教程–信號量
- Java并發教程–重入鎖
- Java并發教程–線程池
- Java并發教程–可調用,將來
- Java并發教程–阻塞隊列
- Exchanger和無GC的Java
- Java Fork / Join進行并行編程
- 使用迭代器時如何避免ConcurrentModificationException
- 改善Java應用程序性能的快速技巧
翻譯自: https://www.javacodegeeks.com/2011/09/java-concurrency-tutorial.html