CountDownLatch和Join都可以讓一個線程等待子線程完成的功能,但CountDownLatch比Join的優勢在哪呢?下面用示例說明
一、首先舉一個Join的使用實例,當然Logger需要自己配置
先是Join類
JoinClass
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class JoinClass extends Thread{
final Logger logger = LoggerFactory.getLogger(JoinClass.class);
String name;
JoinClass(String _name) {
name = _name;
}
@Override
public void run() {
try {
logger.info("{} is running",name);
Thread.sleep(2000);
logger.info("{} is over",name);
}catch (InterruptedException e) {
logger.error("{} , ",name,e);
}
}
}
測試方法
Test
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.concurrent.CountDownLatch;
public class Test {
final static Logger logger = LoggerFactory.getLogger(Main.class);
public void JoinClassTest() {
//join類示例
JoinClass j1 = new JoinClass("j1");
JoinClass j2 = new JoinClass("j2");
JoinClass j3 = new JoinClass("j3");
j1.start();
j2.start();
try {
j1.join();
j2.join();
}catch (InterruptedException e) {
logger.error("j1 and j2,",e);
}
logger.info("j1 and j2 are over, j3 start");
j3.start();
}
}
結果
2018-12-03 20:03:39 INFO [CountDownLatchAndJoin.JoinClass] j1 is running
2018-12-03 20:03:39 INFO [CountDownLatchAndJoin.JoinClass] j2 is running
2018-12-03 20:03:41 INFO [CountDownLatchAndJoin.JoinClass] j1 is over
2018-12-03 20:03:41 INFO [CountDownLatchAndJoin.JoinClass] j2 is over
2018-12-03 20:03:41 INFO [CountDownLatchAndJoin.Main] j1 and j2 are over, j3 start
2018-12-03 20:03:41 INFO [CountDownLatchAndJoin.JoinClass] j3 is running
2018-12-03 20:03:43 INFO [CountDownLatchAndJoin.JoinClass] j3 is over
從結果看出使用Join後,主線程在等待 j1 和 j2 執行完成後纔去調用 j3線程
二、下面是CountDownLatch使用用例
CountDownLatchSimple類
CountDownLatchClass
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.concurrent.CountDownLatch;
public class CountDownLatchSimple extends Thread{
final Logger logger = LoggerFactory.getLogger(CountDownLatchSimple.class);
private CountDownLatch countDownLatch;
String name;
CountDownLatchSimple(String _name, CountDownLatch _countDownLatch) {
name = _name;
countDownLatch=_countDownLatch;
}
@Override
public void run() {
try {
logger.info("{} is running",name);
Thread.sleep(2000);
logger.info("{} is over",name);
countDownLatch.countDown();
}catch (InterruptedException e) {
logger.info("{}",name,e);
}
}
}
測試方法
Test
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.concurrent.CountDownLatch;
public class Test {
final static Logger logger = LoggerFactory.getLogger(Main.class);
public void CountDownLatchSimple() {
//CountDownLatch實現
CountDownLatch countDownLatch = new CountDownLatch(2);
CountDownLatchSimple countDownLatch1 = new CountDownLatchSimple("countDownLatch1",countDownLatch);
CountDownLatchSimple countDownLatch2 = new CountDownLatchSimple("countDownLatch2",countDownLatch);
CountDownLatchSimple countDownLatch3 = new CountDownLatchSimple("countDownLatch3",countDownLatch);
countDownLatch1.start();
countDownLatch2.start();
try {
countDownLatch.await();
}catch (InterruptedException e) {
logger.error("countDownLatch.await,",e);
}
countDownLatch3.start();
}
}
測試結果
2018-12-03 20:15:43 INFO [CountDownLatchAndJoin.CountDownLatchSimple] countDownLatch2 is running
2018-12-03 20:15:43 INFO [CountDownLatchAndJoin.CountDownLatchSimple] countDownLatch1 is running
2018-12-03 20:15:45 INFO [CountDownLatchAndJoin.CountDownLatchSimple] countDownLatch1 is over
2018-12-03 20:15:45 INFO [CountDownLatchAndJoin.CountDownLatchSimple] countDownLatch2 is over
2018-12-03 20:15:45 INFO [CountDownLatchAndJoin.CountDownLatchSimple] countDownLatch3 is running
2018-12-03 20:15:47 INFO [CountDownLatchAndJoin.CountDownLatchSimple] countDownLatch3 is over
從結果看出CountDownLatch實現了和Join一樣的功能
三、但有些功能是否是Join不能實現的呢?看如下代碼
CountDownLatchStage類
CountDownLatchStage
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.concurrent.CountDownLatch;
public class CountDownLatchStage extends Thread{
final Logger logger = LoggerFactory.getLogger(CountDownLatchSimple.class);
private CountDownLatch countDownLatch;
String name;
CountDownLatchStage(String _name, CountDownLatch _countDownLatch) {
name = _name;
countDownLatch=_countDownLatch;
}
@Override
public void run() {
try {
logger.info("{} is running",name);
Thread.sleep(2000);
logger.info("{}'s finished half of work ",name);
countDownLatch.countDown();
Thread.sleep(1000);
logger.info("{}'s is over,end",name);
}catch (InterruptedException e) {
logger.info("{}",name,e);
}
}
}
Test類
Test
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.concurrent.CountDownLatch;
public class Test {
final static Logger logger = LoggerFactory.getLogger(Main.class);
public void CountDownLatchStage() {
//CountDownLatchStage實現
CountDownLatch countDownLatch = new CountDownLatch(2);
CountDownLatchStage countDownLatchStage1 = new CountDownLatchStage("countDownLatchStage1",countDownLatch);
CountDownLatchStage countDownLatchStage2 = new CountDownLatchStage("countDownLatchStage2",countDownLatch);
CountDownLatchStage countDownLatchStage3 = new CountDownLatchStage("countDownLatchStage3",countDownLatch);
countDownLatchStage1.start();
countDownLatchStage2.start();
try {
countDownLatch.await();
}catch (InterruptedException e) {
logger.error("countDownLatch.await,",e);
}
countDownLatchStage3.start();
}
}
結果
2018-12-03 20:20:50 INFO [CountDownLatchAndJoin.CountDownLatchSimple] countDownLatchStage2 is running
2018-12-03 20:20:50 INFO [CountDownLatchAndJoin.CountDownLatchSimple] countDownLatchStage1 is running
2018-12-03 20:20:52 INFO [CountDownLatchAndJoin.CountDownLatchSimple] countDownLatchStage2’s finished half of work
2018-12-03 20:20:52 INFO [CountDownLatchAndJoin.CountDownLatchSimple] countDownLatchStage1’s finished half of work
2018-12-03 20:20:52 INFO [CountDownLatchAndJoin.CountDownLatchSimple] countDownLatchStage3 is running
2018-12-03 20:20:53 INFO [CountDownLatchAndJoin.CountDownLatchSimple] countDownLatchStage2’s is over,end
2018-12-03 20:20:53 INFO [CountDownLatchAndJoin.CountDownLatchSimple] countDownLatchStage1’s is over,end
2018-12-03 20:20:54 INFO [CountDownLatchAndJoin.CountDownLatchSimple] countDownLatchStage3’s finished half of work
2018-12-03 20:20:55 INFO [CountDownLatchAndJoin.CountDownLatchSimple] countDownLatchStage3’s is over,end
從結果看出CountDownLatch可以讓線程在某一階段受它限制,一個線程執行必須依賴CountDownLatch管理的線程的執行完畢才行。
而Join則沒有這種功能,它必須讓子線程執行完畢,才能讓接下來的程序執行。但相對的,join代碼寫起來也相對簡潔,明瞭。
四、最後,突然想到用CountDownLatch實現類似CyclicBarrier的功能,就是讓所有任務都執行完,才進行下一階段。類似一羣羊在跑時,設置一個柵欄,等所有羊都到齊纔開柵欄一樣。
CountDownLatchThreeStage類
CountDownLatchThreeStage
package CountDownLatchAndJoin;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.concurrent.CountDownLatch;
public class CountDownLatchThreeStage extends Thread{
final Logger logger = LoggerFactory.getLogger(CountDownLatchSimple.class);
private CountDownLatch countDownLatch1;
private CountDownLatch countDownLatch2;
String name;
CountDownLatchThreeStage(String _name, CountDownLatch _countDownLatch1,CountDownLatch _countDownLatch2) {
name = _name;
countDownLatch1=_countDownLatch1;
countDownLatch2=_countDownLatch2;
}
@Override
public void run() {
try {
logger.info("{}'s stage1...",name);
Thread.sleep(2000);
countDownLatch1.countDown();
logger.info("{}'s stage2...",name);
Thread.sleep(2000);
countDownLatch2.countDown();
Thread.sleep(1000);
logger.info("{}'s stage3...",name);
}catch (InterruptedException e) {
logger.info("{}",name,e);
}
}
}
Test類
Test
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.concurrent.CountDownLatch;
public class Test {
final static Logger logger = LoggerFactory.getLogger(Main.class);
public void CountDownLatchThreeTasksStage() {
//CountDownLatch 多任務同時進入下一階段,很low,要用Cyclicbarrier
CountDownLatch countDownLatch1 = new CountDownLatch(2);
CountDownLatch countDownLatch2 = new CountDownLatch(2);
CountDownLatchThreeStage countDownLatchStage1 = new CountDownLatchThreeStage("countDownLatchStage1",countDownLatch1,countDownLatch2);
CountDownLatchThreeStage countDownLatchStage2 = new CountDownLatchThreeStage("countDownLatchStage2",countDownLatch1,countDownLatch2);
countDownLatchStage1.start();
countDownLatchStage2.start();
try {
countDownLatch1.await();
countDownLatch2.await();
}catch (InterruptedException e) {
logger.error("countDownLatch.await,",e);
}
}
}
結果
2018-12-03 20:41:01 INFO [CountDownLatchAndJoin.CountDownLatchSimple] countDownLatchStage2’s stage1…
2018-12-03 20:41:01 INFO [CountDownLatchAndJoin.CountDownLatchSimple] countDownLatchStage1’s stage1…
2018-12-03 20:41:03 INFO [CountDownLatchAndJoin.CountDownLatchSimple] countDownLatchStage1’s stage2…
2018-12-03 20:41:03 INFO [CountDownLatchAndJoin.CountDownLatchSimple] countDownLatchStage2’s stage2…
2018-12-03 20:41:06 INFO [CountDownLatchAndJoin.CountDownLatchSimple] countDownLatchStage1’s stage3…
2018-12-03 20:41:06 INFO [CountDownLatchAndJoin.CountDownLatchSimple] countDownLatchStage2’s stage3…
當然,這裏只是舉例。在實用中還是要用CyclicBarrier來讓所有任務完成才進入下一階段。