23. CountDownLatch****類
CountDownLatch類似計(jì)數(shù)器的功能隘截,CountDownLatch是一種靈活的閉鎖實(shí)現(xiàn),能夠使一個(gè)線程在等待另外一些線程完成各自工作之后汹胃,再繼續(xù)執(zhí)行婶芭。使用一個(gè)計(jì)數(shù)器進(jìn)行實(shí)現(xiàn)。計(jì)數(shù)器初始值為線程的數(shù)量着饥。當(dāng)每一個(gè)線程完成自己任務(wù)后犀农,計(jì)數(shù)器的值就會(huì)減一。當(dāng)計(jì)數(shù)器的值為0時(shí)宰掉,表示所有的線程都已經(jīng)完成了任務(wù)井赌,然后在CountDownLatch上等待的線程就可以恢復(fù)執(zhí)行任務(wù)。
需求1:計(jì)算10個(gè)學(xué)生搶蘋果的總時(shí)間贵扰。
問題代碼:
public class NoCountDownLatchDemo {
public static voidmain(String[] args) throws InterruptedException {
long begin = System.currentTimeMillis();
Apple apple= new Apple();
for (int i= 0; i< 10; i++) {
new Thread(apple).start();
}
long end = System.currentTimeMillis();
System.out.println("共耗費(fèi)" + (end- begin) + "ms時(shí)間");
}
}
classApple implements Runnable {
private int appleNum = 100;
@Override
public void run() {
for (int i= 0; i< 1000; i++) {
synchronized (this) {
if (appleNum > 0) {
System.out.println(Thread.currentThread().getName() + "搶到第"+ appleNum-- + "個(gè)蘋果");
}
}
}
}
}
測(cè)試結(jié)果:
[圖片上傳失敗...(image-c7bb34-1548232986922)]
問題分析:
耗費(fèi)總時(shí)間應(yīng)該是蘋果搶完之后才計(jì)算出來的仇穗,現(xiàn)在還在搶的過程中就計(jì)算出來了,所以我們需要在計(jì)算消耗時(shí)間之前設(shè)置一個(gè)關(guān)卡戚绕,判斷搶蘋果線程是否都結(jié)束纹坐,如果都結(jié)束了就執(zhí)行時(shí)間的計(jì)算。
分析如圖所示:
[圖片上傳失敗...(image-332aef-1548232986922)]
正確代碼:
public class CountDownLatchDemo {
public static voidmain(String[] args) throws InterruptedException {
CountDownLatch latch= new CountDownLatch(10);
long begin = System.currentTimeMillis();
Apple1 apple= new Apple1(latch);
for (int i= 0; i< 10; i++) {
new Thread(apple).start();
}
latch.await();//不讓main線程往下運(yùn)行舞丛,直到吃蘋果線程都運(yùn)行完畢耘子,才放行
long end = System.currentTimeMillis();
System.out.println("共耗費(fèi)"+(end-begin)+"ms時(shí)間");
}
}
classApple1 implements Runnable{
private int appleNum = 100;
privateCountDownLatch latch;
publicApple1(CountDownLatch latch) {
this.latch= latch;
}
@Override
public void run() {
try {
for (int i= 0; i< 1000; i++) {
synchronized (this) {
if (appleNum>0) {
System.out.println(Thread.currentThread().getName()+"搶到第"+appleNum--+"個(gè)蘋果");
}
}
}
} finally {//必須要執(zhí)行
latch.countDown();
}
}
}
24. CyclicBarrier****類
CyclicBarrier回環(huán)柵欄果漾,通過它可以實(shí)現(xiàn)讓一組線程等待至某個(gè)狀態(tài)之后再全部同時(shí)執(zhí)行。叫做回環(huán)是因?yàn)楫?dāng)所有等待線程都被釋放以后谷誓,CyclicBarrier可以被重用绒障。我們暫且把這個(gè)狀態(tài)就叫做barrier,當(dāng)調(diào)用await()方法之后捍歪,線程就處于barrier了户辱。
需求:通知10個(gè)線程開會(huì),線程到達(dá)會(huì)議室的時(shí)間是不一致的糙臼,人齊開會(huì)庐镐。
代碼演示:
public class CyclicBarrierDemo {
public static voidmain(String[] args) {
CyclicBarrier barrier= newCyclicBarrier(10, new Runnable() {
@Override
public void run() {
System.out.println("人已經(jīng)到齊,準(zhǔn)備開會(huì)变逃!");
}
});
for (int i= 0; i< 10; i++) {
new Thread(new Meet(barrier)).start();
}
}
}
classMeet implements Runnable {
privateCyclicBarrier barrier;
publicMeet(CyclicBarrier barrier) {
this.barrier= barrier;
}
public void meeting() {
System.out.println(Thread.currentThread().getName() + "到達(dá)會(huì)議室等待");
try {
barrier.await();//中間設(shè)置了一道屏障
} catch(Exception e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "開會(huì)中必逆!");
}
@Override
public void run() {
meeting();
}
}
25. Semaphore****類
Semaphore英文含義為信號(hào)量,Semaphore可以控制同時(shí)訪問的線程個(gè)數(shù)揽乱,通過 acquire() 獲取一個(gè)許可名眉,如果沒有就等待,而 release() 釋放一個(gè)許可凰棉。
需求:模擬車子等紅路燈璧针,綠燈表示線程獲取許可哦,通過馬路渊啰,但是是一批一批的過馬路探橱,過馬路的車輛數(shù)量是固定的,最多不能超過這個(gè)數(shù)绘证。
代碼演示:
public class SemaphoreDemo {
public static voidmain(String[] args) {
Semaphore semaphore= new Semaphore(10);
for (int i= 0; i< 100; i++) {
new Thread(new Car(semaphore)).start();
}
}
}
classCar implements Runnable{
privateSemaphore semaphore;
publicCar(Semaphore semaphore) {
super();
this.semaphore= semaphore;
}
@Override
public void run() {
try {
semaphore.acquire();//綠燈,獲得許可證
Thread.sleep(5000);
System.out.println(Thread.currentThread().getName()+"-->"+"一批一批過馬路");
semaphore.release();//許可證發(fā)完隧膏,轉(zhuǎn)紅燈
} catch(InterruptedException e) {
e.printStackTrace();
}
}
}
26. CountDownLatch****、****CyclicBarrie****嚷那、****Semaphorer****三者的區(qū)別
? CountDownLatch:使一個(gè)線程A或是組線程A等待其它線程執(zhí)行完畢后胞枕,一個(gè)線程A或是組線程A才繼續(xù)執(zhí)行(發(fā)現(xiàn)參差不齊,等一等魏宽,重新在起步)腐泻。CyclicBarrier:等所有的線程到達(dá)一個(gè)點(diǎn),中間做完barrierAction的事情之后队询,才能重新各自做各自的事情派桩。(人齊來會(huì),開會(huì)后蚌斩,各自完成各自任務(wù))Semaphore:一批一批線程執(zhí)行
? CountDownLatch是減計(jì)數(shù)方式铆惑,計(jì)數(shù)==0時(shí)釋放所有等待的線程;CyclicBarrier是加計(jì)數(shù)方式,計(jì)數(shù)達(dá)到指定的值時(shí)釋放所有等待的線程员魏。Semaphore調(diào)用semaphore.acquire()得到一個(gè)許可丑蛤,當(dāng)許可到了一定的數(shù)量時(shí)可以開始執(zhí)行線程.
? CountDownLatch當(dāng)計(jì)數(shù)到0時(shí),計(jì)數(shù)無法被重置撕阎;CyclicBarrier計(jì)數(shù)達(dá)到指定值時(shí)受裹,此時(shí)計(jì)數(shù)設(shè)置為0,又可以重新開始虏束。
? CountDownLatch每次調(diào)用countDown()方法計(jì)數(shù)減一棉饶,調(diào)用await()方法只進(jìn)行阻塞,對(duì)計(jì)數(shù)沒任何影響魄眉;CyclicBarrier只有一個(gè)await()方法,調(diào)用await()方法計(jì)數(shù)加1闷袒,若加1后的值不等于構(gòu)造方法的值坑律,則線程阻塞。
? CountDownLatch囊骤、CyclikBarrier這個(gè)值作為計(jì)數(shù)用晃择,達(dá)到該次數(shù)即釋放等待的線程,而Semaphore 中所有acquire獲取到的資源達(dá)到這個(gè)數(shù)也物,會(huì)使得其它線程阻塞宫屠。