CountDownLatch和Join的使用实例以及比较

  • Post author:
  • Post category:其他


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来让所有任务完成才进入下一阶段。



版权声明:本文为HaloTrriger原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。