CountDownLatch和Join的使用實例以及比較

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來讓所有任務完成才進入下一階段。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章