java并发中CountDownLatch的使用
文章目錄
- 主線程等待子線程全都結束之后再開始運行
- 等待所有線程都準備好再一起執行
- 停止CountdownLatch的await
java并發中CountDownLatch的使用
在java并發中,控制共享變量的訪問非常重要,有時候我們也想控制并發線程的執行順序,比如:等待所有線程都執行完畢之后再執行另外的線程,或者等所有線程都準備好了才開始所有線程的執行等。
這個時候我們就可以使用到CountDownLatch。
簡單點講,CountDownLatch存有一個放在QueuedSynchronizer中的計數器。當調用countdown() 方法時,該計數器將會減一。然后再調用await()來等待計數器歸零。
private static final class Sync extends AbstractQueuedSynchronizer {... }private final Sync sync;public void countDown() {sync.releaseShared(1);} public void await() throws InterruptedException {sync.acquireSharedInterruptibly(1);}public boolean await(long timeout, TimeUnit unit)throws InterruptedException {return sync.tryAcquireSharedNanos(1, unit.toNanos(timeout));}下面我們舉兩個使用的例子:
主線程等待子線程全都結束之后再開始運行
這里我們定義子線程類,在子線程類里面,我們傳入一個CountDownLatch用來計數,然后在子線程結束之前,調用該CountDownLatch的countDown方法。最后在主線程中調用await()方法來等待子線程結束執行。
@Slf4j public class MainThreadWaitUsage implements Runnable {private List<String> outputScraper;private CountDownLatch countDownLatch;public MainThreadWaitUsage(List<String> outputScraper, CountDownLatch countDownLatch) {this.outputScraper = outputScraper;this.countDownLatch = countDownLatch;}@Overridepublic void run() {outputScraper.add("Counted down");countDownLatch.countDown();} }看下怎么調用:
@Testpublic void testCountDownLatch()throws InterruptedException {List<String> outputScraper = Collections.synchronizedList(new ArrayList<>());CountDownLatch countDownLatch = new CountDownLatch(5);List<Thread> workers = Stream.generate(() -> new Thread(new MainThreadWaitUsage(outputScraper, countDownLatch))).limit(5).collect(toList());workers.forEach(Thread::start);countDownLatch.await();outputScraper.add("Latch released");log.info(outputScraper.toString());}執行結果如下:
07:37:27.388 [main] INFO MainThreadWaitUsageTest - [Counted down, Counted down, Counted down, Counted down, Counted down, Latch released]等待所有線程都準備好再一起執行
上面的例子中,我們是主線程等待子線程,那么在這個例子中,我們將會看看怎么子線程一起等待到準備好的狀態,再一起執行。
思路也很簡單,在子線程開始之后,將等待的子線程計數器減一,在主線程中await該計數器,等計數器歸零之后,主線程再通知子線程運行。
public class ThreadWaitThreadUsage implements Runnable {private List<String> outputScraper;private CountDownLatch readyThreadCounter;private CountDownLatch callingThreadBlocker;private CountDownLatch completedThreadCounter;public ThreadWaitThreadUsage(List<String> outputScraper,CountDownLatch readyThreadCounter,CountDownLatch callingThreadBlocker,CountDownLatch completedThreadCounter) {this.outputScraper = outputScraper;this.readyThreadCounter = readyThreadCounter;this.callingThreadBlocker = callingThreadBlocker;this.completedThreadCounter = completedThreadCounter;}@Overridepublic void run() {readyThreadCounter.countDown();try {callingThreadBlocker.await();outputScraper.add("Counted down");} catch (InterruptedException e) {e.printStackTrace();} finally {completedThreadCounter.countDown();}} }看下怎么調用:
@Testpublic void testCountDownLatch()throws InterruptedException {List<String> outputScraper = Collections.synchronizedList(new ArrayList<>());CountDownLatch readyThreadCounter = new CountDownLatch(5);CountDownLatch callingThreadBlocker = new CountDownLatch(1);CountDownLatch completedThreadCounter = new CountDownLatch(5);List<Thread> workers = Stream.generate(() -> new Thread(new ThreadWaitThreadUsage(outputScraper, readyThreadCounter, callingThreadBlocker, completedThreadCounter))).limit(5).collect(toList());workers.forEach(Thread::start);readyThreadCounter.await();outputScraper.add("Workers ready");callingThreadBlocker.countDown();completedThreadCounter.await();outputScraper.add("Workers complete");log.info(outputScraper.toString());}輸出結果如下:
07:41:47.861 [main] INFO ThreadWaitThreadUsageTest - [Workers ready, Counted down, Counted down, Counted down, Counted down, Counted down, Workers complete]停止CountdownLatch的await
如果我們調用await()方法,該方法將會等待一直到count=0才結束。但是如果在線程執行過程中出現了異常,可能導致countdown方法執行不了。那么await()方法可能會出現無限等待的情況。
這個時候我們可以使用:
public boolean await(long timeout, TimeUnit unit)throws InterruptedException {return sync.tryAcquireSharedNanos(1, unit.toNanos(timeout));}本文的例子可以參考https://github.com/ddean2009/learn-java-concurrency/tree/master/CountDownLatch
更多精彩內容且看:
- 區塊鏈從入門到放棄系列教程-涵蓋密碼學,超級賬本,以太坊,Libra,比特幣等持續更新
- Spring Boot 2.X系列教程:七天從無到有掌握Spring Boot-持續更新
- Spring 5.X系列教程:滿足你對Spring5的一切想象-持續更新
- java程序員從小工到專家成神之路(2020版)-持續更新中,附詳細文章教程
更多教程請參考 flydean的博客
總結
以上是生活随笔為你收集整理的java并发中CountDownLatch的使用的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: java中Locks的使用
- 下一篇: 在java中使用JMH(Java Mic