什么时候使用CountDownLatch
正如每個(gè)Java文檔所描述的那樣,CountDownLatch是一個(gè)同步工具類,它允許一個(gè)或多個(gè)線程一直等待,直到其他線程的操作執(zhí)行完后再執(zhí)行。在Java并發(fā)中,countdownlatch的概念是一個(gè)常見的面試題,所以一定要確保你很好的理解了它。在這篇文章中,我將會(huì)涉及到在Java并發(fā)編 程中跟CountDownLatch相關(guān)的以下幾點(diǎn):
目錄
- CountDownLatch是什么?
- CountDownLatch如何工作?
- 在實(shí)時(shí)系統(tǒng)中的應(yīng)用場(chǎng)景
- 應(yīng)用范例
- 常見的面試題
CountDownLatch是什么
CountDownLatch是在java1.5被引入的,跟它一起被引入的并發(fā)工具類還有CyclicBarrier、Semaphore、ConcurrentHashMap和BlockingQueue,它們都存在于java.util.concurrent包下。CountDownLatch這個(gè)類能夠使一個(gè)線程等待其他線程完成各自的工作后再執(zhí)行。例如,應(yīng)用程序的主線程希望在負(fù)責(zé)啟動(dòng)框架服務(wù)的線程已經(jīng)啟動(dòng)所有的框架服務(wù)之后再執(zhí)行。
CountDownLatch是通過一個(gè)計(jì)數(shù)器來實(shí)現(xiàn)的,計(jì)數(shù)器的初始值為線程的數(shù)量。每當(dāng)一個(gè)線程完成了自己的任務(wù)后,計(jì)數(shù)器的值就會(huì)減1。當(dāng)計(jì)數(shù)器值到達(dá)0時(shí),它表示所有的線程已經(jīng)完成了任務(wù),然后在閉鎖上等待的線程就可以恢復(fù)執(zhí)行任務(wù)。
CountDownLatch的偽代碼如下所示:
| 1 2 3 4 5 6 | //Main thread start //Create CountDownLatch for N threads //Create and start N threads //Main thread wait on latch //N threads completes there tasks are returns //Main thread resume execution |
CountDownLatch如何工作
CountDownLatch.java類中定義的構(gòu)造函數(shù):
| 1 2 | //Constructs a CountDownLatch initialized with the given count. public void CountDownLatch(int count) {...} |
構(gòu)造器中的計(jì)數(shù)值(count)實(shí)際上就是閉鎖需要等待的線程數(shù)量。這個(gè)值只能被設(shè)置一次,而且CountDownLatch沒有提供任何機(jī)制去重新設(shè)置這個(gè)計(jì)數(shù)值。
與CountDownLatch的第一次交互是主線程等待其他線程。主線程必須在啟動(dòng)其他線程后立即調(diào)用CountDownLatch.await()方法。這樣主線程的操作就會(huì)在這個(gè)方法上阻塞,直到其他線程完成各自的任務(wù)。
其他N 個(gè)線程必須引用閉鎖對(duì)象,因?yàn)樗麄冃枰ㄖ狢ountDownLatch對(duì)象,他們已經(jīng)完成了各自的任務(wù)。這種通知機(jī)制是通過?CountDownLatch.countDown()方法來完成的;每調(diào)用一次這個(gè)方法,在構(gòu)造函數(shù)中初始化的count值就減1。所以當(dāng)N個(gè)線程都調(diào) 用了這個(gè)方法,count的值等于0,然后主線程就能通過await()方法,恢復(fù)執(zhí)行自己的任務(wù)。
在實(shí)時(shí)系統(tǒng)中的使用場(chǎng)景
讓我們嘗試羅列出在java實(shí)時(shí)系統(tǒng)中CountDownLatch都有哪些使用場(chǎng)景。我所羅列的都是我所能想到的。如果你有別的可能的使用方法,請(qǐng)?jiān)诹粞岳锪谐鰜?#xff0c;這樣會(huì)幫助到大家。
CountDownLatch使用例子
在這個(gè)例子中,我模擬了一個(gè)應(yīng)用程序啟動(dòng)類,它開始時(shí)啟動(dòng)了n個(gè)線程類,這些線程將檢查外部系統(tǒng)并通知閉鎖,并且啟動(dòng)類一直在閉鎖上等待著。一旦驗(yàn)證和檢查了所有外部服務(wù),那么啟動(dòng)類恢復(fù)執(zhí)行。
BaseHealthChecker.java:這個(gè)類是一個(gè)Runnable,負(fù)責(zé)所有特定的外部服務(wù)健康的檢測(cè)。它刪除了重復(fù)的代碼和閉鎖的中心控制代碼。
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 | public abstract class BaseHealthChecker implements Runnable { ????private CountDownLatch _latch; ????private String _serviceName; ????private boolean _serviceUp; ????//Get latch object in constructor so that after completing the task, thread can countDown() the latch ????public BaseHealthChecker(String serviceName, CountDownLatch latch) ????{ ????????super(); ????????this._latch = latch; ????????this._serviceName = serviceName; ????????this._serviceUp = false; ????} ????@Override ????public void run() { ????????try { ????????????verifyService(); ????????????_serviceUp = true; ????????} catch (Throwable t) { ????????????t.printStackTrace(System.err); ????????????_serviceUp = false; ????????} finally { ????????????if(_latch != null) { ????????????????_latch.countDown(); ????????????} ????????} ????} ????public String getServiceName() { ????????return _serviceName; ????} ????public boolean isServiceUp() { ????????return _serviceUp; ????} ????//This methos needs to be implemented by all specific service checker ????public abstract void verifyService(); } |
NetworkHealthChecker.java:這個(gè)類繼承了BaseHealthChecker,實(shí)現(xiàn)了verifyService()方法。DatabaseHealthChecker.java和CacheHealthChecker.java除了服務(wù)名和休眠時(shí)間外,與NetworkHealthChecker.java是一樣的。
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | public class NetworkHealthChecker extends BaseHealthChecker { ????public NetworkHealthChecker (CountDownLatch latch)? { ????????super("Network Service", latch); ????} ????@Override ????public void verifyService() ????{ ????????System.out.println("Checking " + this.getServiceName()); ????????try ????????{ ????????????Thread.sleep(7000); ????????} ????????catch (InterruptedException e) ????????{ ????????????e.printStackTrace(); ????????} ????????System.out.println(this.getServiceName() + " is UP"); ????} } |
ApplicationStartupUtil.java:這個(gè)類是一個(gè)主啟動(dòng)類,它負(fù)責(zé)初始化閉鎖,然后等待,直到所有服務(wù)都被檢測(cè)完。
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 | public class ApplicationStartupUtil { ????//List of service checkers ????private static List<BaseHealthChecker> _services; ????//This latch will be used to wait on ????private static CountDownLatch _latch; ????private ApplicationStartupUtil() ????{ ????} ????private final static ApplicationStartupUtil INSTANCE = new ApplicationStartupUtil(); ????public static ApplicationStartupUtil getInstance() ????{ ????????return INSTANCE; ????} ????public static boolean checkExternalServices() throws Exception ????{ ????????//Initialize the latch with number of service checkers ????????_latch = new CountDownLatch(3); ????????//All add checker in lists ????????_services = new ArrayList<BaseHealthChecker>(); ????????_services.add(new NetworkHealthChecker(_latch)); ????????_services.add(new CacheHealthChecker(_latch)); ????????_services.add(new DatabaseHealthChecker(_latch)); ????????//Start service checkers using executor framework ????????Executor executor = Executors.newFixedThreadPool(_services.size()); ????????for(final BaseHealthChecker v : _services) ????????{ ????????????executor.execute(v); ????????} ????????//Now wait till all services are checked ????????_latch.await(); ????????//Services are file and now proceed startup ????????for(final BaseHealthChecker v : _services) ????????{ ????????????if( ! v.isServiceUp()) ????????????{ ????????????????return false; ????????????} ????????} ????????return true; ????} } |
現(xiàn)在你可以寫測(cè)試代碼去檢測(cè)一下閉鎖的功能了。
| 1 2 3 4 5 6 7 8 9 10 11 12 | public class Main { ????public static void main(String[] args) ????{ ????????boolean result = false; ????????try { ????????????result = ApplicationStartupUtil.checkExternalServices(); ????????} catch (Exception e) { ????????????e.printStackTrace(); ????????} ????????System.out.println("External services validation completed !! Result was :: "+ result); ????} } |
| 1 2 3 4 5 6 7 8 9 | Output in console: Checking Network Service Checking Cache Service Checking Database Service Database Service is UP Cache Service is UP Network Service is UP External services validation completed !! Result was :: true |
常見面試題
可以為你的下次面試準(zhǔn)備以下一些CountDownLatch相關(guān)的問題:
- 解釋一下CountDownLatch概念?
- CountDownLatch 和CyclicBarrier的不同之處?
- 給出一些CountDownLatch使用的例子?
- ?CountDownLatch 類中主要的方法?
下載上述例子的源代碼,請(qǐng)點(diǎn)擊如下鏈接:
- 源碼下載? ?
也上傳一份到csdn了,可免費(fèi)下載http://download.csdn.net/detail/u012373717/9674633
轉(zhuǎn)載于:https://www.cnblogs.com/felixzh/p/6036151.html
總結(jié)
以上是生活随笔為你收集整理的什么时候使用CountDownLatch的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Sprint2-3.0
- 下一篇: Dynamics CRM 开启图表的3