天天看點

記一次項目中CountDownLatch的坑

項目背景

1、Android項目;

2、依賴httpclient請求中的異步傳回資料;

2、countDownLatch用來構造一個同步場景,傳回httpclient請求的response資料,await逾時時間10s;

3、線程池數量:4;

問題現象

在網絡比較慢的場景下,多次在前端觸發該業務流程,大機率出現每一次的click事件,都會觸發線程countDownLatch.await的10s逾時;

關鍵詞

多線程、countDownLatch、線程池耗盡、逾時

定位過程

通過增加日志可發現,httpclient的接口耗時遠遠低于10s的逾時時間,調用httpclient前列印入口日志,均正常列印調用,接口均正常傳回,且耗時較短,則判斷該逾時并非服務端問題;

列印日志大約時間如下:

先列印4條調用httpclient的日志,然後過10s列印await逾時日志,之後再列印接口請求回調日志,判斷是回調過慢導緻await逾時;

猜測:由于線程池數量有限,await操作阻塞目前線程,導緻回調方法無法搶占到線程,最終造成逾時;

CountDownLatch原理

概念:這個類使一個線程,等其他線程執行完畢後再執行;是通過計數器來實作的,對象初始化時設定一個int值為需要等到的線程數量,一個等待線程執行完畢後 -1,等數量歸零後,在閉鎖上等待的線程就可以繼續執行了。

源碼:

// count為計數值
public CountDownLatch(int count){}

//調用await()方法的線程會被挂起,它會等待直到count值為0才繼續執行
public void await() throws InterruptedException { };   
//和await()類似,隻不過等待一定的時間後count值還沒變為0的話就會繼續執行
public boolean await(long timeout, TimeUnit unit) throws InterruptedException { };  
//将count值減1
public void countDown() { }; 
           

常見使用常見:用于進行接口時間優化,将串行流程分割成并行場景,減少調用時間;

什麼是閉鎖??

閉鎖——是一種Synchronizer對象,它根據本身的狀态調節線程的控制流,常見的Synchronizer包括信号量、關卡、閉鎖。

AQS

https://www.jianshu.com/p/0f876ead2846