闭锁java_java多线程学习十::::CountDownLatch闭锁
請(qǐng)看以下的代碼
package rs.thread.day0504;
import java.util.concurrent.CountDownLatch;
/**
* @auther rs
* @date 2019/5/4 20:32
* @email 529811807@qq.com
* @weixinhao javawjs
*
*/
public class Test10_CountDownLatch {
public static void main(String [] args ){
//執(zhí)行時(shí)間
long startTime = System.currentTimeMillis();
//這個(gè)是控制幾個(gè)線程在執(zhí)行后,在執(zhí)行主線程的任務(wù)
int count = 6;
CountDownLatch ld = new CountDownLatch(count);
for(int j =0;j
new Thread(new CountDownLatchThread(ld)){}.start();
}
//等待數(shù)得到0這個(gè)數(shù)據(jù)在執(zhí)行
try {
ld.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
long endTime = System.currentTimeMillis();
System.out.println("使用的時(shí)間是>>" + (endTime - startTime));
}
}
class CountDownLatchThread implements Runnable{
private CountDownLatch latch ;
public CountDownLatchThread(){}
public CountDownLatchThread(CountDownLatch latch){
this.latch = latch;
}
@Override
public void run() {
for(int i = 0;i<50000;i++){
if(i % 2 == 0){
System.out.println(i);
}
}
//必須控制它減少到0
latch.countDown();
}
}
看了上面的定義和Demo代碼之后,使用就會(huì)簡(jiǎn)單一點(diǎn)了,一般流程如首先是創(chuàng)建實(shí)例 CountDownLatch countDown = new CountDownLatch(2)
需要同步的線程執(zhí)行完之后,計(jì)數(shù)-1; countDown.countDown()
需要等待其他線程執(zhí)行完畢之后,再運(yùn)行的線程,調(diào)用 countDown.await()實(shí)現(xiàn)阻塞同步
注意在創(chuàng)建實(shí)例是,必須指定初始的計(jì)數(shù)值,且應(yīng)大于0
必須有線程中顯示的調(diào)用了countDown()計(jì)數(shù)-1方法;必須有線程顯示調(diào)用了 await()方法(沒有這個(gè)就沒有必要使用CountDownLatch了)
由于await()方法會(huì)阻塞到計(jì)數(shù)為0,如果在代碼邏輯中某個(gè)線程漏掉了計(jì)數(shù)-1,導(dǎo)致最終計(jì)數(shù)一直大于0,直接導(dǎo)致死鎖了
鑒于上面一點(diǎn),更多的推薦 await(long, TimeUnit)來(lái)替代直接使用await()方法,至少不會(huì)造成阻塞死只能重啟的情況
應(yīng)用場(chǎng)景
前面給了一個(gè)demo演示如何用,那這個(gè)東西在實(shí)際的業(yè)務(wù)場(chǎng)景中是否會(huì)用到呢?
因?yàn)榇_實(shí)在一個(gè)業(yè)務(wù)場(chǎng)景中使用到了,不然也就不會(huì)單獨(dú)撈出這一節(jié)...
電商的詳情頁(yè),由眾多的數(shù)據(jù)拼裝組成,如可以分成一下幾個(gè)模塊交易的收發(fā)貨地址,銷量
商品的基本信息(標(biāo)題,圖文詳情之類的)
推薦的商品列表
評(píng)價(jià)的內(nèi)容
....
上面的幾個(gè)模塊信息,都是從不同的服務(wù)獲取信息,且彼此沒啥關(guān)聯(lián);所以為了提高響應(yīng),完全可以做成并發(fā)獲取數(shù)據(jù),如線程1獲取交易相關(guān)數(shù)據(jù)
線程2獲取商品基本信息
線程3獲取推薦的信息
線程4獲取評(píng)價(jià)信息
....
但是最終拼裝數(shù)據(jù)并返回給前端,需要等到上面的所有信息都獲取完畢之后,才能返回,這個(gè)場(chǎng)景就非常的適合 CountDownLatch來(lái)做了在拼裝完整數(shù)據(jù)的線程中調(diào)用 CountDownLatch#await(long, TimeUnit) 等待所有的模塊信息返回
每個(gè)模塊信息的獲取,由一個(gè)獨(dú)立的線程執(zhí)行;執(zhí)行完畢之后調(diào)用 CountDownLatch#countDown() 進(jìn)行計(jì)數(shù)-1
CountDownLatch實(shí)現(xiàn)原理就是AQS 的原理
這么好用的功能是怎么實(shí)現(xiàn)的呢,下面就來(lái)說(shuō)一說(shuō)實(shí)現(xiàn)它的核心技術(shù)原理 AQS。 AQS 全稱 AbstractQueuedSynchronizer,是 java.util.concurrent 中提供的一種高效且可擴(kuò)展的同步機(jī)制。它可以用來(lái)實(shí)現(xiàn)可以依賴 int 狀態(tài)的同步器,獲取和釋放參數(shù)以及一個(gè)內(nèi)部FIFO等待隊(duì)列,除了CountDownLatch,ReentrantLock、Semaphore 等功能實(shí)現(xiàn)都使用了它。
接下來(lái)用 CountDownLatch 來(lái)分析一下 AQS 的實(shí)現(xiàn)。建議看文章的時(shí)候先大致看一下源碼,有助于理解下面所說(shuō)的內(nèi)容。
在我們的方法中調(diào)用 awit()和countDown()的時(shí)候,發(fā)生了幾個(gè)關(guān)鍵的調(diào)用關(guān)系,我畫了一個(gè)方法調(diào)用圖。
首先在 CountDownLatch 類內(nèi)部定義了一個(gè) Sync 內(nèi)部類,這個(gè)內(nèi)部類就是繼承自 AbstractQueuedSynchronizer 的。并且重寫了方法 tryAcquireShared和tryReleaseShared。例如當(dāng)調(diào)用 awit()方法時(shí),CountDownLatch 會(huì)調(diào)用內(nèi)部類Sync 的 acquireSharedInterruptibly() 方法,然后在這個(gè)方法中會(huì)調(diào)用 tryAcquireShared 方法,這個(gè)方法就是 CountDownLatch 的內(nèi)部類 Sync 里重寫的 AbstractQueuedSynchronizer 的方法。調(diào)用 countDown() 方法同理。
這種方式是使用 AbstractQueuedSynchronizer 的標(biāo)準(zhǔn)化方式,大致分為兩步:
1、內(nèi)部持有繼承自 AbstractQueuedSynchronizer 的對(duì)象 Sync;
2、并在 Sync 內(nèi)重寫 AbstractQueuedSynchronizer protected 的部分或全部方法,這些方法包括如下幾個(gè):
總結(jié)
1、AQS 分為獨(dú)占模式和共享模式,CountDownLatch 使用了它的共享模式。
2、AQS 當(dāng)?shù)谝粋€(gè)等待線程(被包裝為 Node)要入隊(duì)的時(shí)候,要保證存在一個(gè) head 節(jié)點(diǎn),這個(gè) head 節(jié)點(diǎn)不關(guān)聯(lián)線程,也就是一個(gè)虛節(jié)點(diǎn)。
3、當(dāng)隊(duì)列中的等待節(jié)點(diǎn)(關(guān)聯(lián)線程的,非 head 節(jié)點(diǎn))搶到鎖,將這個(gè)節(jié)點(diǎn)設(shè)置為 head 節(jié)點(diǎn)。
4、第一次自旋搶鎖失敗后,waitStatus 會(huì)被設(shè)置為 -1(SIGNAL),第二次再失敗,就會(huì)被 LockSupport 阻塞掛起。
5、如果一個(gè)節(jié)點(diǎn)的前置節(jié)點(diǎn)為 SIGNAL 狀態(tài),則這個(gè)節(jié)點(diǎn)可以嘗試搶占鎖。
歡迎轉(zhuǎn)載,轉(zhuǎn)載請(qǐng)注明出處!
github: rs1314
歡迎關(guān)注共公眾號(hào)微信 : java微技術(shù)
分享我的學(xué)習(xí)之路和各種java技術(shù),教程資料
總結(jié)
以上是生活随笔為你收集整理的闭锁java_java多线程学习十::::CountDownLatch闭锁的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: thinkphp scws mysql_
- 下一篇: java字面量 方法区_(一)java的