CountDownLatch
可以理解為線程的計(jì)數(shù)器骂维,使一個(gè)線程等待一組線程執(zhí)行完以后在執(zhí)行惹资,初始值為線程數(shù)的值,當(dāng)一個(gè)線程執(zhí)行完以后航闺,計(jì)數(shù)器的值減1褪测,當(dāng)計(jì)數(shù)器為0時(shí),表示計(jì)數(shù)器上所有線程數(shù)執(zhí)行完成潦刃,開始執(zhí)行后續(xù)的任務(wù)侮措。且不支持計(jì)數(shù)器重置,當(dāng)計(jì)數(shù)器為0后乖杠,當(dāng)其他線程調(diào)await時(shí)分扎,會(huì)直接通過。
先寫個(gè)簡(jiǎn)單的例子:
@Override
public void run(ApplicationArguments args) throws Exception{
//創(chuàng)建固定線程數(shù)胧洒,來測(cè)試計(jì)數(shù)器的使用
ExecutorService executorService = Executors.newFixedThreadPool(5);
//初始化計(jì)數(shù)器
CountDownLatch countDownLatch = new CountDownLatch(5);
for (int i = 0; i < 5; i++) {
Runnable runnable = new Runnable() {
@Override
public void run() {
try {
log.info("runnable start--> Threadname:{}",Thread.currentThread().getName());
Thread.sleep(1000);
log.info("runnable end--> Threadname:{}",Thread.currentThread().getName());
countDownLatch.countDown();//線程執(zhí)行完減1
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
executorService.execute(runnable);
}
log.info("main --> 等待子線程執(zhí)行完N废拧!卫漫!");
//獲取計(jì)數(shù)器值
log.info("current count -->{}",countDownLatch.getCount());
//阻塞菲饼,等待計(jì)數(shù)器執(zhí)行完
//如果設(shè)置了超時(shí)時(shí)間,到時(shí)間會(huì)直接走下面的線程
//countDownLatch.await(100, TimeUnit.MILLISECONDS);
countDownLatch.await();
log.info("main 開始執(zhí)行汛兜。巴粪。。");
log.info("current count -->{}",countDownLatch.getCount());
}
執(zhí)行結(jié)果:
2019-12-05 20:14:31.302 INFO 1160 --- [pool-1-thread-5] com.laod.MemcachedApplication : runnable start--> Threadname:pool-1-thread-5
2019-12-05 20:14:31.301 INFO 1160 --- [pool-1-thread-3] com.laod.MemcachedApplication : runnable start--> Threadname:pool-1-thread-3
2019-12-05 20:14:31.301 INFO 1160 --- [pool-1-thread-4] com.laod.MemcachedApplication : runnable start--> Threadname:pool-1-thread-4
2019-12-05 20:14:31.302 INFO 1160 --- [ main] com.laod.MemcachedApplication : main --> 等待子線程執(zhí)行完!8馗辫塌!
2019-12-05 20:14:31.300 INFO 1160 --- [pool-1-thread-1] com.laod.MemcachedApplication : runnable start--> Threadname:pool-1-thread-1
2019-12-05 20:14:31.300 INFO 1160 --- [pool-1-thread-2] com.laod.MemcachedApplication : runnable start--> Threadname:pool-1-thread-2
2019-12-05 20:14:31.302 INFO 1160 --- [ main] com.laod.MemcachedApplication : current count -->5
2019-12-05 20:14:32.306 INFO 1160 --- [pool-1-thread-5] com.laod.MemcachedApplication : runnable end--> Threadname:pool-1-thread-5
2019-12-05 20:14:32.306 INFO 1160 --- [pool-1-thread-2] com.laod.MemcachedApplication : runnable end--> Threadname:pool-1-thread-2
2019-12-05 20:14:32.306 INFO 1160 --- [pool-1-thread-4] com.laod.MemcachedApplication : runnable end--> Threadname:pool-1-thread-4
2019-12-05 20:14:32.306 INFO 1160 --- [pool-1-thread-1] com.laod.MemcachedApplication : runnable end--> Threadname:pool-1-thread-1
2019-12-05 20:14:32.306 INFO 1160 --- [pool-1-thread-3] com.laod.MemcachedApplication : runnable end--> Threadname:pool-1-thread-3
2019-12-05 20:14:32.307 INFO 1160 --- [ main] com.laod.MemcachedApplication : main 開始執(zhí)行。派哲。臼氨。
2019-12-05 20:14:32.307 INFO 1160 --- [ main] com.laod.MemcachedApplication : current count -->0
CyclicBarrier
上面的CountDownLatch,如果業(yè)務(wù)需兩個(gè)線程步調(diào)一致芭届,然后在通知其他線程储矩,雖然CountDownLatch也可以做,定義計(jì)數(shù)器2褂乍,每個(gè)線程執(zhí)行完后都減1持隧,如果計(jì)數(shù)器大于0,就線程1或者線程2等待逃片,如果計(jì)數(shù)器等于0屡拨,就喚醒線程1,線程2褥实,在執(zhí)行其他線程呀狼。
雖然這樣也可以實(shí)現(xiàn),兩線程步調(diào)一致损离,但是較繁瑣哥艇,Java并發(fā)包內(nèi)有現(xiàn)成的可以使用:CyclicBarrier,與上面很打一個(gè)區(qū)別僻澎,這個(gè)有自動(dòng)重置貌踏,回調(diào)方法的功能,當(dāng)減到 0 的時(shí)候窟勃,會(huì)自動(dòng)重置你設(shè)置的初始值哩俭,循環(huán)執(zhí)行 直接上例子:
@Override
public void run(ApplicationArguments args) throws Exception{
// 業(yè)務(wù)1
Vector<String> pos = new Vector<String>();
// 業(yè)務(wù)2
Vector<String> dos = new Vector<String>();
//創(chuàng)建固定線程數(shù),來測(cè)試計(jì)數(shù)器的使用
ExecutorService executor = Executors.newFixedThreadPool(2);
//從字面意思就能理解 可循環(huán)利用
CyclicBarrier barrier = new CyclicBarrier(2,() ->{
executor.execute(()->check(pos,dos));
});
//業(yè)務(wù)1
Thread T1 = new Thread(()->{
while (1==1){
//處理具體的業(yè)務(wù)
try {
log.info("模擬業(yè)務(wù)1一直有數(shù)據(jù)");
pos.add("1");
barrier.await();
log.info("numberwaiting -->{}",barrier.getNumberWaiting());
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
}
});
T1.start();
//業(yè)務(wù)2
Thread T2 = new Thread(()->{
while (1==1){
//處理具體的業(yè)務(wù)
try {
log.info("模擬業(yè)務(wù)2一直有數(shù)據(jù)");
dos.add("2");
barrier.await();
log.info("numberwaiting -->{}",barrier.getNumberWaiting());
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
}
});
T2.start();
log.debug("-----");
}
private void check(Vector<String> pos, Vector<String> dos) {
pos.remove(0);
dos.remove(0);
log.info("--- 處理業(yè)務(wù)場(chǎng)景 步調(diào)一致");
}
執(zhí)行結(jié)果如下拳恋,可以很清楚看到兩線程業(yè)務(wù)處理完成后,在做其他處理:
2019-12-06 09:28:02.067 INFO 1698 --- [ Thread-9] com.laod.MemcachedApplication : 模擬業(yè)務(wù)1一直有數(shù)據(jù)
2019-12-06 09:28:02.067 INFO 1698 --- [ Thread-10] com.laod.MemcachedApplication : 模擬業(yè)務(wù)2一直有數(shù)據(jù)
2019-12-06 09:28:02.068 INFO 1698 --- [pool-1-thread-1] com.laod.MemcachedApplication : --- 處理業(yè)務(wù)場(chǎng)景 步調(diào)一致
2019-12-06 09:28:02.068 INFO 1698 --- [ Thread-9] com.laod.MemcachedApplication : numberwaiting -->0
2019-12-06 09:28:02.068 INFO 1698 --- [ Thread-10] com.laod.MemcachedApplication : numberwaiting -->0
2019-12-06 09:28:02.071 INFO 1698 --- [ Thread-10] com.laod.MemcachedApplication : 模擬業(yè)務(wù)2一直有數(shù)據(jù)
2019-12-06 09:28:03.071 INFO 1698 --- [ Thread-9] com.laod.MemcachedApplication : 模擬業(yè)務(wù)1一直有數(shù)據(jù)
2019-12-06 09:28:03.072 INFO 1698 --- [ Thread-9] com.laod.MemcachedApplication : numberwaiting -->0
2019-12-06 09:28:03.072 INFO 1698 --- [ Thread-10] com.laod.MemcachedApplication : numberwaiting -->0
2019-12-06 09:28:03.074 INFO 1698 --- [ Thread-10] com.laod.MemcachedApplication : 模擬業(yè)務(wù)2一直有數(shù)據(jù)
2019-12-06 09:28:03.075 INFO 1698 --- [pool-1-thread-2] com.laod.MemcachedApplication : --- 處理業(yè)務(wù)場(chǎng)景 步調(diào)一致
2019-12-06 09:28:04.077 INFO 1698 --- [ Thread-9] com.laod.MemcachedApplication : 模擬業(yè)務(wù)1一直有數(shù)據(jù)
2019-12-06 09:28:04.077 INFO 1698 --- [ Thread-10] com.laod.MemcachedApplication : numberwaiting -->0
2019-12-06 09:28:04.077 INFO 1698 --- [pool-1-thread-1] com.laod.MemcachedApplication : --- 處理業(yè)務(wù)場(chǎng)景 步調(diào)一致
2019-12-06 09:28:04.077 INFO 1698 --- [ Thread-9] com.laod.MemcachedApplication : numberwaiting -->0
2019-12-06 09:28:04.079 INFO 1698 --- [ Thread-10] com.laod.MemcachedApplication : 模擬業(yè)務(wù)2一直有數(shù)據(jù)
2019-12-06 09:28:05.083 INFO 1698 --- [ Thread-9] com.laod.MemcachedApplication : 模擬業(yè)務(wù)1一直有數(shù)據(jù)
2019-12-06 09:28:05.084 INFO 1698 --- [ Thread-9] com.laod.MemcachedApplication : numberwaiting -->0
2019-12-06 09:28:05.084 INFO 1698 --- [ Thread-10] com.laod.MemcachedApplication : numberwaiting -->0
2019-12-06 09:28:05.084 INFO 1698 --- [pool-1-thread-2] com.laod.MemcachedApplication : --- 處理業(yè)務(wù)場(chǎng)景 步調(diào)一致
2019-12-06 09:28:05.085 INFO 1698 --- [ Thread-10] com.laod.MemcachedApplication : 模擬業(yè)務(wù)2一直有數(shù)據(jù)
2019-12-06 09:28:06.089 INFO 1698 --- [ Thread-9] com.laod.MemcachedApplication : 模擬業(yè)務(wù)1一直有數(shù)據(jù)
2019-12-06 09:28:06.089 INFO 1698 --- [pool-1-thread-1] com.laod.MemcachedApplication : --- 處理業(yè)務(wù)場(chǎng)景 步調(diào)一致
2019-12-06 09:28:06.089 INFO 1698 --- [ Thread-10] com.laod.MemcachedApplication : numberwaiting -->0
2019-12-06 09:28:06.089 INFO 1698 --- [ Thread-9] com.laod.MemcachedApplication : numberwaiting -->0
2019-12-06 09:28:06.091 INFO 1698 --- [ Thread-10] com.laod.MemcachedApplication : 模擬業(yè)務(wù)2一直有數(shù)據(jù)
2019-12-06 09:28:07.091 INFO 1698 --- [ Thread-9] com.laod.MemcachedApplication : 模擬業(yè)務(wù)1一直有數(shù)據(jù)
2019-12-06 09:28:07.091 INFO 1698 --- [ Thread-9] com.laod.MemcachedApplication : numberwaiting -->0
2019-12-06 09:28:07.091 INFO 1698 --- [ Thread-10] com.laod.MemcachedApplication : numberwaiting -->0
2019-12-06 09:28:07.091 INFO 1698 --- [pool-1-thread-2] com.laod.MemcachedApplication : --- 處理業(yè)務(wù)場(chǎng)景 步調(diào)一致
2019-12-06 09:28:07.092 INFO 1698 --- [ Thread-10] com.laod.MemcachedApplication : 模擬業(yè)務(wù)2一直有數(shù)據(jù)
2019-12-06 09:28:08.096 INFO 1698 --- [ Thread-9] com.laod.MemcachedApplication : 模擬業(yè)務(wù)1一直有數(shù)據(jù)
2019-12-06 09:28:08.096 INFO 1698 --- [ Thread-10] com.laod.MemcachedApplication : numberwaiting -->0
2019-12-06 09:28:08.096 INFO 1698 --- [ Thread-9] com.laod.MemcachedApplication : numberwaiting -->0
2019-12-06 09:28:08.096 INFO 1698 --- [pool-1-thread-1] com.laod.MemcachedApplication : --- 處理業(yè)務(wù)場(chǎng)景 步調(diào)一致
2019-12-06 09:28:08.098 INFO 1698 --- [ Thread-10] com.laod.MemcachedApplication : 模擬業(yè)務(wù)2一直有數(shù)據(jù)
總結(jié):
CountDownLatch:
業(yè)務(wù)場(chǎng)景:一個(gè)線程等待多個(gè)線程的執(zhí)行場(chǎng)景砸捏,不能循環(huán)利用谬运,一旦計(jì)數(shù)器為0后,且有線程調(diào)用await()垦藏,會(huì)直接通過梆暖。
CyclicBarrier:
業(yè)務(wù)場(chǎng)景:一組線程之間相互等待,可循環(huán)利用掂骏,計(jì)數(shù)器為0后轰驳,會(huì)自動(dòng)重置,而且還支持回調(diào)函數(shù)。
完