概述
通過(guò)常見(jiàn)并發(fā)工具類(lèi)來(lái)實(shí)現(xiàn)多線程之間的調(diào)度:CountDownLatch层释、CyclicBarrier再愈、Semaphore铛楣、Thread.join()
- CountDownLatch:主刀荒、子線程同步(1+N的同步)。阻塞主線程窄陡,等待指定個(gè)數(shù)的子線程完成后炕淮,再執(zhí)行主線程。依賴(lài) 1個(gè)await + N個(gè)countDown 兩個(gè)函數(shù)完成功能
- CyclicBarrier(柵欄):N個(gè)子線程的同步跳夭。讓多個(gè)子線程阻塞涂圆,滿(mǎn)足一定數(shù)量的await函數(shù)調(diào)用后,所有子線程繼續(xù)執(zhí)行后面的邏輯币叹。依賴(lài) N個(gè)await完成阻塞和計(jì)數(shù)润歉。
- Semaphore:多線程限流。通過(guò)初始化參數(shù)指定允許最高并發(fā)線程颈抚,用阻塞等待的方式限流踩衩。但是功能沒(méi)有JUC線程池豐富(無(wú)法復(fù)用線程)。依賴(lài) require + release 兩個(gè)函數(shù)完成功能
- 其實(shí)Thread.join()也可以實(shí)現(xiàn) 1+1的線程同步贩汉,只不過(guò)控制沒(méi)有CountDownLatch靈活驱富。線程的同步機(jī)制,依賴(lài)于子線程徹底運(yùn)行結(jié)束匹舞,但是可以保證可見(jiàn)性褐鸥。而CountDownLatch不需要等待子線程結(jié)束,只要計(jì)數(shù)滿(mǎn)足N赐稽,阻塞線程就可以繼續(xù)執(zhí)行
CountDownLatch
通過(guò)latch.await方法阻塞主線程叫榕,多個(gè)子線程調(diào)用latch.countDown(),latch來(lái)負(fù)責(zé)計(jì)數(shù)姊舵,來(lái)完成一個(gè)大的任務(wù)
比如5個(gè)子任務(wù)的下載晰绎,主線程阻塞,等待5個(gè)子線程都下載完畢括丁,主線程才喚醒寒匙,打印下載完畢
public static void main(String[] args) throws InterruptedException {
final CountDownLatch latch = new CountDownLatch(5);
for(int i = 0; i < 5; i++){
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
try {
System.out.println(Thread.currentThread().getName() + " 開(kāi)始下載");
Thread.sleep(1000);
System.out.println(Thread.currentThread().getName() + " 完成下載");
latch.countDown();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
thread.start();
}
latch.await();
System.out.println("全部下載完畢");
}
CyclicBarrier(柵欄 子線程同步)
阻塞引用的所有的子線程,直到滿(mǎn)足一定的條件躏将,所有的子線程才回復(fù)工作。但是和CDL不同考蕾,更簡(jiǎn)潔祸憋,子線程調(diào)用 CyclicBarrier.await()的時(shí)候,不僅阻塞當(dāng)前子線程肖卧,而且計(jì)數(shù)會(huì)減少1蚯窥。不需要額外調(diào)用別的方法。
通過(guò)它可以實(shí)現(xiàn)讓一組線程等待至某個(gè)狀態(tài)之后再全部同時(shí)執(zhí)行。這個(gè)阻塞的是所有的子線程拦赠,一直到都完成大家在一起往下執(zhí)行巍沙。而不是阻塞主線程
支持回調(diào)方法
@Override
public void run() {
try{
System.out.println("子線程: 子任務(wù)"+taskCode+"已準(zhǔn)備就緒,等待其他子任務(wù)就緒荷鼠。句携。。");
begin_cyclicBarrier.await();
System.out.println("子線程: 子任務(wù)"+taskCode+"開(kāi)始執(zhí)行");
Thread.sleep(1000);
count.addAndGet(Integer.valueOf(taskCode));
System.out.println("子線程: 子任務(wù)"+taskCode+"執(zhí)行完成");
end_cyclicBarrier.await();
}catch(Exception e){
}
}
Semaphore(多線程限流)
多線程限流允乐,通過(guò)控制初始化參數(shù)矮嫉,控制最大支持的并發(fā)數(shù),從而限流,semaphore.acquire 計(jì)數(shù)牍疏,semaphore.release釋放蠢笋。但是功能沒(méi)有線程池的豐富。
在限流方面鳞陨,類(lèi)似線程池昨寞,但是不具備線程池的復(fù)用線程、線程數(shù)控制厦滤、飽和策略等功能
線程池的邏輯是:core線程援岩、BlockingQueue、max線程馁害、丟棄窄俏。
信號(hào)量的邏輯:進(jìn)入計(jì)數(shù),釋放計(jì)數(shù)碘菜,總量控制凹蜈,阻塞等待。
限制最多N個(gè)線程同時(shí)運(yùn)行忍啸,超出的線程爭(zhēng)奪會(huì)阻塞仰坦,直到有線程release。這和線程池的maxCore類(lèi)似但是不一樣计雌。
//測(cè)試類(lèi)50個(gè)線程準(zhǔn)備接水悄晃,但是水龍頭只有10個(gè)
public class Test {
public static void main(String[] args) throws InterruptedException {
final Semaphore semaphore=new Semaphore(10);
for(int i=0;i<50;i++){
TestThread thread=new TestThread(semaphore,i+1);
thread.start();
}
}
}
public class TestThread extends Thread{
Semaphore semaphore;
int number=0;
TestThread(Semaphore semaphore,int number){
this.semaphore=semaphore;
this.number=number;
}
@Override
public void run() {
try {
semaphore.acquire();
System.out.println("學(xué)生"+this.number+"開(kāi)始接水...");
Thread.sleep(2000);
System.out.println("學(xué)生"+this.number+"接水完畢");
semaphore.release();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}