java并發(fā)編程JUC CountDownLatch線(xiàn)程同步
java并發(fā)編程JUC CountDownLatch線(xiàn)程同步
CountDownLatch是一種線(xiàn)程同步輔助工具,它允許一個(gè)或多個(gè)線(xiàn)程等待其他線(xiàn)程正在執(zhí)行的一組操作完成。CountDownLatch的概念在java并發(fā)編程中非常常見(jiàn),面試也會(huì)經(jīng)常被問(wèn)到,所以一定要好好理解掌握。
CountDownLatch與其他并發(fā)編程工具類(lèi),如CyclicBarrier、Semaphore、ConcurrentHashMap和BlockingQueue等在java.util.concurrent包中與JDK 1.5一起被引入。CountDownLatch能讓一個(gè)java線(xiàn)程等待其他線(xiàn)程完成任務(wù),比如Application的主線(xiàn)程等待,直到其他負(fù)責(zé)啟動(dòng)框架服務(wù)的服務(wù)線(xiàn)程完成所有服務(wù)的啟動(dòng)。
1、CountDownLatch是什么?
CountDownLatch用線(xiàn)程數(shù)來(lái)初始化一個(gè)計(jì)數(shù)器,每當(dāng)一個(gè)線(xiàn)程完成執(zhí)行時(shí),這個(gè)計(jì)數(shù)器就會(huì)遞減。當(dāng)計(jì)數(shù)為零時(shí),表示所有線(xiàn)程都已完成執(zhí)行,處于等待狀態(tài)的主線(xiàn)程可以繼續(xù)執(zhí)行。
下面我們使用偽代碼的方式描述CountDownLatch 的作用
- 主線(xiàn)程啟動(dòng),并為N個(gè)線(xiàn)程(假設(shè)n=3)初始化CountDownLatch(n)
- 啟動(dòng)n個(gè)線(xiàn)程
- 主線(xiàn)程阻塞等待
- 線(xiàn)程1執(zhí)行完成,CountDownLatch -1 = 2,主線(xiàn)程繼續(xù)阻塞
- 線(xiàn)程3執(zhí)行完成,CountDownLatch -1 = 1,主線(xiàn)程繼續(xù)阻塞
- 線(xiàn)程4執(zhí)行完成,CountDownLatch -1 = 0,主線(xiàn)程恢復(fù)執(zhí)行
2、CountDownLatch 如何工作
CountDownLatch.java類(lèi)里面定義了一個(gè)構(gòu)造函數(shù)。count實(shí)質(zhì)上是線(xiàn)程數(shù),這個(gè)值只能設(shè)置一次,CountDownLatch沒(méi)有提供方法來(lái)重置這個(gè)數(shù)。
CountDownLatch.public CountDownLatch(int count) {...}
使用CountDownLatch的主線(xiàn)程要去等待其他線(xiàn)程執(zhí)行完成,所以這個(gè)主線(xiàn)程必須在啟動(dòng)其他線(xiàn)程后立即調(diào)用 CountDownLatch.await() 方法,該方法阻塞主線(xiàn)程處于等待狀態(tài),直到其他線(xiàn)程執(zhí)行完畢,才會(huì)停止阻塞。
其他N個(gè)線(xiàn)程必須有CountDownLatch對(duì)象的引用,因?yàn)樗鼈冃枰ㄖ狢ountDownLatch對(duì)象它們已經(jīng)完成任務(wù)。這個(gè)通知是由方法CountDownLatch.countDown()
來(lái)完成的,每調(diào)用一次該方法,就會(huì)將構(gòu)造函數(shù)中設(shè)置的初始計(jì)數(shù)count減少1,所以當(dāng)所有N個(gè)線(xiàn)程都調(diào)用了這個(gè)方法后count計(jì)數(shù)達(dá)到0,主線(xiàn)程就可以不受await()方法阻塞恢復(fù)執(zhí)行了。
所以CountDownLatch特別適合于那些需要等待N個(gè)線(xiàn)程完成后再開(kāi)始執(zhí)行
的場(chǎng)景。例如一個(gè)應(yīng)用程序的啟動(dòng)類(lèi),在處理用戶(hù)請(qǐng)求之前,要確保所有N個(gè)外部系統(tǒng)都是處于運(yùn)行狀態(tài)的。
3、CountDownLatch 代碼例子
假設(shè)我們的應(yīng)用程序主線(xiàn)程啟動(dòng)之前,要檢查另外4個(gè)程序是否準(zhǔn)備就緒,只有其他的4個(gè)程序準(zhǔn)備就緒,我們的主程序才能繼續(xù)執(zhí)行。就可以使用下面的代碼來(lái)操作:
import java.util.concurrent.CountDownLatch; public class Tester { public static void main(String args[]) { //設(shè)置計(jì)數(shù)器 counter = 4 ,等于線(xiàn)程數(shù) CountDownLatch countDownLatch = new CountDownLatch(4); Thread app1 = new Thread(new Application("App1", countDownLatch)); Thread app2 = new Thread(new Application("App2", countDownLatch)); Thread app3 = new Thread(new Application("App3", countDownLatch)); Thread app4 = new Thread(new Application("App4", countDownLatch)); // 啟動(dòng)多線(xiàn)程去檢查其他四個(gè)程序的可用狀態(tài) app1.start(); app2.start(); app3.start(); app4.start(); try { //主線(xiàn)程調(diào)用await進(jìn)行等待,等待上述四個(gè)線(xiàn)程正常完成 countDownLatch.await(); //上述四個(gè)線(xiàn)程檢查的應(yīng)用程序啟動(dòng)正常之后, 打印如下信息 System.out.println("All applications are up and running."); } catch(InterruptedException e) { System.out.println(e.getMessage()); } } }
子線(xiàn)程程序,每一個(gè)線(xiàn)程都持有countDownLatch對(duì)象,線(xiàn)程正常執(zhí)行完成之時(shí),使用countDownLatch.countDown()方法將countDownLatch對(duì)象的計(jì)數(shù)器減1。
class Application implements Runnable { private String name; //應(yīng)用程序名稱(chēng) private CountDownLatch countDownLatch; public Application(String name, CountDownLatch countDownLatch) { this.name = name; this.countDownLatch = countDownLatch; } public void run() { try { System.out.println(name + " started. "); Thread.sleep(1000); } catch (InterruptedException e) { System.out.println(e.getMessage()); } System.out.println( name + " is Up and running."); //將countDownLatch計(jì)數(shù)器的值減1 countDownLatch.countDown(); } }
上述程序的打印輸出結(jié)果是,可以結(jié)合輸出結(jié)果去理解上文中講述的CountDownLatch 工作原理:
App2 started. App3 started. App1 started. App4 started. App1 is Up and running. App3 is Up and running. App4 is Up and running. App2 is Up and running. All applications are up and running.
到此這篇關(guān)于java并發(fā)編程JUC CountDownLatch線(xiàn)程同步的文章就介紹到這了,更多相關(guān)java JUC CountDownLatch線(xiàn)程同步內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
輕松理解Java面試和開(kāi)發(fā)中的IoC(控制反轉(zhuǎn))
在Java開(kāi)發(fā)中,IoC意 味著將你設(shè)計(jì)好的類(lèi)交給系統(tǒng)去控制,而不是在你的類(lèi)內(nèi)部控制。這稱(chēng)為控制反轉(zhuǎn)。下文給大家介紹Java面試和開(kāi)發(fā)中的IoC(控制反轉(zhuǎn))知識(shí),需要的朋友參考下吧2017-07-07使用ServletInputStream在攔截器或過(guò)濾器中應(yīng)用后重寫(xiě)
這篇文章主要介紹了使用ServletInputStream在攔截器或過(guò)濾器中應(yīng)用后重寫(xiě),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-10-10Springboot?通過(guò)FastJson實(shí)現(xiàn)bean對(duì)象和Json字符串互轉(zhuǎn)問(wèn)題
這篇文章主要介紹了Springboot?通過(guò)FastJson實(shí)現(xiàn)bean對(duì)象和Json字符串互轉(zhuǎn),本文嘗試驗(yàn)證兩種場(chǎng)景給大家詳細(xì)介紹,對(duì)Springboot?FastJson實(shí)現(xiàn)bean和Json互轉(zhuǎn)問(wèn)題,感興趣的朋友一起看看吧2022-08-08MyBatis實(shí)現(xiàn)動(dòng)態(tài)SQL的實(shí)現(xiàn)方法
這篇文章主要介紹了MyBatis實(shí)現(xiàn)動(dòng)態(tài)SQL的實(shí)現(xiàn)方法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-12-12自定義注解實(shí)現(xiàn)Spring容器注入Bean方式(類(lèi)似于mybatis的@MapperScans)
本文介紹了如何通過(guò)自定義注解@MyService和@MyServiceScans在SpringBoot項(xiàng)目中自動(dòng)將指定包下的類(lèi)注入Spring容器,詳細(xì)解釋了創(chuàng)建自定義注解、定義包掃描器ClassPathBeanDefinitionScanner的作用與實(shí)現(xiàn)2024-09-09關(guān)于mybatis3中幾個(gè)@Provider的使用方式
這篇文章主要介紹了關(guān)于mybatis3中幾個(gè)@Provider的使用方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-07-07Spring?Kafka中如何通過(guò)參數(shù)配置解決超時(shí)問(wèn)題詳解
這篇文章主要給大家介紹了關(guān)于Spring?Kafka中如何通過(guò)參數(shù)配置解決超時(shí)問(wèn)題的相關(guān)資料,文中通過(guò)實(shí)例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2022-01-01使用@PathVariable注解如何實(shí)現(xiàn)動(dòng)態(tài)傳值
這篇文章主要介紹了使用@PathVariable注解如何實(shí)現(xiàn)動(dòng)態(tài)傳值,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-10-10