1.CountDownLatch和CyclicBarrier的相似處和不同處:
CountDownLatch是通過(guò)一個(gè)計(jì)數(shù)器來(lái)實(shí)現(xiàn)的,當(dāng)我們?cè)趎ew 一個(gè)CountDownLatch對(duì)象的時(shí)候需要帶入該計(jì)數(shù)器值,該值就表示了線程的數(shù)量。每當(dāng)一個(gè)線程完成自己的任務(wù)后,計(jì)數(shù)器的值就會(huì)減1。當(dāng)計(jì)數(shù)器的值變?yōu)?時(shí),就表示所有的線程均已經(jīng)完成了任務(wù),然后就可以恢復(fù)等待的線程繼續(xù)執(zhí)行了。
雖然,CountDownlatch與CyclicBarrier有那么點(diǎn)相似,但是他們還是存在一些區(qū)別的:
CountDownLatch的作用是允許1或N個(gè)線程等待其他線程完成執(zhí)行;而CyclicBarrier則是允許N個(gè)線程相互等待
CountDownLatch的計(jì)數(shù)器無(wú)法被重置;CyclicBarrier的計(jì)數(shù)器可以被重置后使用,因此它被稱為是循環(huán)的barrier。
CountDownLatch最關(guān)鍵的一個(gè)參數(shù)就是count。
CountDownLatch的幾個(gè)核心方法:
? await()方法 //countDownLatch的await()方法會(huì)使當(dāng)前線程在鎖存器倒計(jì)數(shù)至零之前,一直等待,除非線程被中斷。
? countDown()方法? // countDown()方法可以遞減鎖存器的計(jì)數(shù),如果計(jì)數(shù)到達(dá)零,則釋放所有等待的線程。
總結(jié)起來(lái),就是CountDownLatch有三個(gè)核心部分:
? ? ? ? ? ? p1.是 count? 計(jì)數(shù)器
? ? p2.是 await()方法,使當(dāng)前線程阻塞,直到count的值為0。
? ? p3.是 countDown()方法,使計(jì)數(shù)器器的值減一。
應(yīng)用場(chǎng)景是這樣的:
線程A的運(yùn)行需要同時(shí)擁有N個(gè)資源,而這N個(gè)資源卻被n1,n2,n3, ......,nn個(gè)線程分別占有者。
所以:A要想運(yùn)行的話,它就必須等待n1,n2,n3,......,nn這n個(gè)線程都把各自占有的資源釋放了才行。
其實(shí),它就是一把 共享資源鎖。
2.用一段故事說(shuō)明一下
相當(dāng)于現(xiàn)在有一個(gè)保險(xiǎn)柜,這個(gè)保險(xiǎn)柜上有三把鎖,只有把這三把鎖都打開才能打開保險(xiǎn)柜 。而這三把鎖卻被分別交給了三個(gè)管理員A,B,C手中。所以,如果我們想打開這個(gè)保險(xiǎn)柜的話,就必須集齊所有的三把鎖。
有一天老板來(lái)視察工作,想看下保險(xiǎn)柜的錢少了,沒有,就找來(lái)經(jīng)理。讓經(jīng)理開門,經(jīng)理說(shuō),你等一下,我打三個(gè)電話,把人叫齊了才能把門打開。你現(xiàn)在必須先等一下。于是,經(jīng)理叫開始逐個(gè)打電話,他先打給A,"趕快帶上鑰匙來(lái)公司一趟,老板在等著你",1分鐘后,A來(lái)了,帶來(lái)了一把鑰匙。然后,經(jīng)理繼續(xù)給B打電話,"兄弟,趕快來(lái)公司一趟,把鑰匙帶上,老板要檢查保險(xiǎn)柜"。2分鐘后,B來(lái)了。最后,經(jīng)理又給C打了一個(gè)電話,"你他娘的,帶上鑰匙趕快來(lái)公司。" 5分鐘后,C也來(lái)了,就這樣。老板在等候了8分鐘后終于集齊了三把鑰匙,打開了保險(xiǎn)柜,看到了自己的小金庫(kù)。經(jīng)過(guò)漫長(zhǎng)而艱辛的等待他欣慰地漏出了笑容。
3.demo案例
需求:
過(guò)來(lái)一個(gè)請(qǐng)求,這個(gè)請(qǐng)求傳遞過(guò)來(lái)一個(gè)集合,要求我們分別算出該集合元素的總和、積、所有偶數(shù)值,并存入庫(kù)中,然后把處理結(jié)果返回客戶端。
3.1 創(chuàng)建三個(gè)負(fù)責(zé)和、積、偶數(shù)值的Runnable
public class AddRunnable implements Runnable {
private? CountDownLatch? countDown;
private? List<Integer>? dataList;
public AddRunnable(CountDownLatch countDown,List<Integer> dataList) {
super();
this.countDown = countDown;
this.dataList = dataList;
}
@Override
public void run() {
Thread.currentThread().setName("sum線程");
//計(jì)算和
Long sum=0l;
for (Integer value : dataList) {
sum=sum+value;
}
//計(jì)算出來(lái)總和后,把結(jié)果存庫(kù)
System.out.println("計(jì)算結(jié)果是:"+sum+"? 把計(jì)算結(jié)果存庫(kù)!");
countDown.countDown();//釋放鎖
System.out.println(Thread.currentThread().getName()+"釋放了一把共享鎖");
}
}
乘積:
public class MultiRunnable implements Runnable {
private? CountDownLatch? countDown;
private? List<Integer>? dataList;
public MultiRunnable(CountDownLatch countDown, List<Integer> dataList) {
super();
this.countDown = countDown;
this.dataList = dataList;
}
@Override
public void run() {
// TODO Auto-generated method stub
Thread.currentThread().setName("muti線程");
//計(jì)算和
Long muti=1l;
for (Integer value : dataList) {
muti=muti*value;
System.out.println(muti);
}
//計(jì)算出來(lái)總和后,把結(jié)果存庫(kù)
System.out.println("乘積結(jié)果是:"+muti+"? 把乘積結(jié)果存庫(kù)!");
countDown.countDown();//釋放鎖
System.out.println(Thread.currentThread().getName()+"釋放了一把共享鎖");
}
}
所有偶數(shù)值:
public class OddRunnable implements Runnable {
? ? private? CountDownLatch? countDown;
private? List<Integer>? dataList;
public OddRunnable(CountDownLatch countDown, List<Integer> dataList) {
super();
this.countDown = countDown;
this.dataList = dataList;
}
@Override
public void run() {
// TODO Auto-generated method stub
// TODO Auto-generated method stub
Thread.currentThread().setName("odd線程");
List<Integer> oddList=new ArrayList<Integer>();
// 計(jì)算和
for (Integer value : dataList) {
if(value%2==0) {
oddList.add(value);
}
}
// 計(jì)算出來(lái)總和后,把結(jié)果存庫(kù)
System.out.println("求偶結(jié)果是:" + oddList.size() + "? 把求偶結(jié)果存庫(kù)!");
countDown.countDown();// 釋放鎖
System.out.println(Thread.currentThread().getName() + "釋放了一把共享鎖");
}
}
測(cè)試:
/**
* 需求:
*? ? 過(guò)來(lái)一個(gè)請(qǐng)求,這個(gè)請(qǐng)求傳遞過(guò)來(lái)一個(gè)集合,要求我們分別算出該集合元素的總和、積、所有偶數(shù)值,并存入庫(kù)中,然后把處理結(jié)果返回客戶端。
* @author chihaojie
*
*/
public class CountDownLatchTest {
private static? CountDownLatch? countDown;
public static void main(String[] args) {
//只有在其他三個(gè)子運(yùn)算全部完成時(shí),當(dāng)前線程才能繼續(xù)
//ExecutorService executorService = Executors.newFixedThreadPool(3);
List<Integer>? dataList=new ArrayList<Integer>();
? ? ? ? for (int i = 0; i < 10; i++) {
? ? ? ? dataList.add(i+1);
}
? ? ? ? System.out.println(dataList);
? ? ? //處理
? ? ? ? countDown=new CountDownLatch(3);
? ? ? ? //開啟三個(gè)線程
? ? ? ? new Thread(new AddRunnable(countDown,? dataList)).start();;
? ? ? ? new Thread(new MultiRunnable(countDown, dataList)).start();;
? ? ? ? new Thread(new OddRunnable(countDown, dataList)).start();;
? ? ? ? //執(zhí)行
? ? ? ? try {
countDown.await();
System.out.println("所有的線程都運(yùn)算完了");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
