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

