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

本文对比分析了CountDownLatch和Join在多线程控制中的不同应用,CountDownLatch支持更灵活的阶段控制,允许线程在部分任务完成时继续,而Join则确保所有子线程完全结束后主线程才继续。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值