Java使用CountDownLatch實(shí)現(xiàn)統(tǒng)計(jì)任務(wù)耗時(shí)
1.什么是閉鎖
在介紹本篇文章之前,先介紹下什么是閉鎖?閉鎖是一種同步的工具類,可以延遲線程的進(jìn)度直到其到達(dá)終止?fàn)顟B(tài),可以把閉鎖看作是一扇門,在閉鎖到達(dá)結(jié)束狀態(tài)之前,這扇門一直是關(guān)閉的,并且沒有任何線程能通過,當(dāng)?shù)竭_(dá)結(jié)束狀態(tài)時(shí),這扇門會打開允許所有線程通過。需要注意的是,當(dāng)閉鎖到達(dá)結(jié)束狀態(tài)后,將不會再改變狀態(tài),因此這扇門將會永遠(yuǎn)保持打開狀態(tài)。閉鎖可以用來確保某些任務(wù)直到其他任務(wù)都完成才繼續(xù)執(zhí)行。
2.閉鎖的使用場景
閉鎖在開發(fā)過程中的用途非常廣,總結(jié)下來主要有以下幾個(gè)場景會用到閉鎖
2.1.確保某個(gè)計(jì)算在資源初始后再繼續(xù)執(zhí)行
在這種場景下我們可以使用二元閉鎖,二元閉鎖包括兩個(gè)狀態(tài),可以用來表示“資源已經(jīng)被初始化”,而所有需要用到資源R的操作都必須在這個(gè)閉鎖上等待。例如我們需要加載一個(gè)配置文件,根據(jù)配置文件去做一些操作就可以使用這種閉鎖的方式;
2.2.確保某個(gè)服務(wù)在其依賴的所有其他服務(wù)都啟動之后才啟動
每個(gè)服務(wù)都有一個(gè)相關(guān)的二元閉鎖。當(dāng)啟動服務(wù)S時(shí),將首先在S依賴的其他服務(wù)閉鎖上等待,在所有依賴的服務(wù)都啟動后會釋放閉鎖S,這樣其他依賴S的服務(wù)才能繼續(xù)執(zhí)行。例如在Android的Aidl服務(wù)綁定的時(shí)候,客戶端綁定服務(wù)端獲取Binder對象時(shí),大概會有個(gè)30ms(不精確)的延遲,如果設(shè)計(jì)SDK的時(shí)候,綁定服務(wù)端和啟動其他調(diào)用服務(wù)端的操作又是并行的情況下,就會出現(xiàn)binder為空的情況,這里就可以使用閉鎖來實(shí)現(xiàn)。具體的實(shí)現(xiàn)手法有興趣的話下次單獨(dú)出一篇文章介紹。
2.3.等待直到某個(gè)操作的所有參與者都就緒再繼續(xù)執(zhí)行
這里舉一個(gè)大家很熟悉的例子,王者榮耀的匹配,每次匹配都需要你自己的隊(duì)友和對面的對手在內(nèi)的所有玩家都就緒后才能開始游戲,不然就會出現(xiàn)少打多的滑稽情況了。這種場景下,當(dāng)所有的玩家都準(zhǔn)備就緒時(shí),閉鎖將會達(dá)到結(jié)束狀態(tài)。
3. CountDownLatch
CountDownLatch 是閉鎖的一種實(shí)現(xiàn),可以在我們上面的各種場景中使用,它可以使一個(gè)或者多個(gè)線程等待一組事件發(fā)生,閉鎖狀態(tài)包括一個(gè)計(jì)數(shù)器,該計(jì)數(shù)器被初始化為一個(gè)正數(shù),表示需要等待的事件數(shù)量,countDown方法遞減計(jì)數(shù)器,表示有一個(gè)事件已經(jīng)發(fā)生了,而await方法會一直阻塞直到計(jì)數(shù)器達(dá)到零。這表示所有等待的事件都已經(jīng)發(fā)生,如果計(jì)數(shù)器的值非零,那么await會一直阻塞直到計(jì)數(shù)器為零,或者等待中的線程中斷,或等待超時(shí)
3.1 使用CountDownLatch統(tǒng)計(jì)多個(gè)工作線程執(zhí)行的耗時(shí)
大致原理是使用兩個(gè)閉鎖,一個(gè)開始門,一個(gè)結(jié)束門,開始門計(jì)數(shù)器初始值為1,結(jié)束門的初始值為工作線程的數(shù)量,所有工作線程首先要做的事情就是在開始門上等待,從而確保所有線程都就緒后才開始執(zhí)行,每個(gè)線程套作的最后一件事情是調(diào)用結(jié)束門的countDown方法減一。demo代碼如下所示:
public static long timeTasks(int nThreads, final Runnable task) throws InterruptedException { final CountDownLatch startGate = new CountDownLatch(1); final CountDownLatch endGate = new CountDownLatch(nThreads); for (int i = 0; i < nThreads; i++){ Thread t = new Thread(){ public void run(){ try { System.out.println("startGate before========"); startGate.await(); System.out.println("startGate after========"); try{ task.run(); }finally { endGate.countDown(); System.out.println("endGate.countDown()========"); } } catch (InterruptedException ignored) {} } }; t.start(); } long start = System.nanoTime(); System.out.println("start========" + start); startGate.countDown(); System.out.println("endGate before========"); endGate.await(); long end = System.nanoTime(); System.out.println("end========" + end); return end-start; }
注意:上面的代碼中,也許讀者會發(fā)現(xiàn)為啥要在timeTask()中使用閉鎖,而不是線程一創(chuàng)建后就立即啟動,因?yàn)槿绻趧?chuàng)建線程后就立即啟動他們,那么先啟動的線程將“領(lǐng)先”后啟動的線程,并且活躍的線程數(shù)量會隨著時(shí)間的推移而增加或者減少,競爭程度也在不斷發(fā)生變化。啟動門將使得主線程能夠同時(shí)釋放所有工作線程,而結(jié)束門則使主線程能夠等待最后一個(gè)線程執(zhí)行完成,而不是順序地等待每個(gè)線程執(zhí)行完成
到此這篇關(guān)于Java使用CountDownLatch實(shí)現(xiàn)統(tǒng)計(jì)任務(wù)耗時(shí)的文章就介紹到這了,更多相關(guān)Java CountDownLatch內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
詳解Java獲取環(huán)境變量及系統(tǒng)屬性的方法
這篇文章主要介紹了詳解Java獲取環(huán)境變量及系統(tǒng)屬性的方法,講解了System.getEnv()和System.getProperties()這兩個(gè)核心方法的使用,需要的朋友可以參考下2016-05-05Java NIO三大組件與ByteBuffer深入理解及使用
這篇文章主要介紹了Java NIO三大組件與ByteBuffer,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)吧2023-01-01Java使用MySQL實(shí)現(xiàn)連接池代碼實(shí)例
這篇文章主要介紹了Java使用MySQL實(shí)現(xiàn)連接池代碼實(shí)例,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-03-03Java實(shí)現(xiàn)斷點(diǎn)下載功能的示例代碼
當(dāng)下載一個(gè)很大的文件時(shí),如果下載到一半暫停,如果繼續(xù)下載呢?斷點(diǎn)下載就是解決這個(gè)問題的。本文將用Java語言實(shí)現(xiàn)斷點(diǎn)下載,需要的可以參考一下2022-05-05Java中public關(guān)鍵字用法詳細(xì)講解
這篇文章主要給大家介紹了關(guān)于Java中public關(guān)鍵字用法的相關(guān)資料,public關(guān)鍵字是和訪問權(quán)限相關(guān)的,它所修飾的方法對所有類都是可以訪問的,需要的朋友可以參考下2023-09-09java生成字母數(shù)字組合的隨機(jī)數(shù)示例 java生成隨機(jī)數(shù)
這篇文章主要介紹了java生成字母數(shù)字組合的隨機(jī)數(shù)的示例,大家參考使用吧2014-01-01Java 中的 BufferedWriter 介紹_動力節(jié)點(diǎn)Java學(xué)院整理
BufferedWriter 是緩沖字符輸出流。它繼承于Writer。接下來通過本文給大家分享Java 中的 BufferedWriter知識,需要的朋友參考下吧2017-05-05解決MyBatis返回結(jié)果類型為Boolean的問題
這篇文章主要介紹了解決MyBatis返回結(jié)果類型為Boolean的問題,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-11-11