CountDownLatch

CountDownLatch是什么

CountDownLatch是在java1.5被引入的,跟它一起被引入的并发工具类还有CyclicBarrier(https://blog.csdn.net/kavito/article/details/81584580)、Semaphore、ConcurrentHashMapBlockingQueue,它们都存在于java.util.concurrent包下。CountDownLatch是一个同步工具类,用来协调多个线程之间的同步,或者说起到线程之间的通信。CountDownLatch能够使一个线程在等待另外一些线程完成各自工作之后,再继续执行。使用一个计数器进行实现。计数器初始值为线程的数量。当每一个线程完成自己任务后,计数器的值就会减一。当计数器的值为0时,表示所有的线程都已经完成了任务,然后在CountDownLatch上等待的线程就可以恢复执行任务。

CountDownLatch的用法

CountDownLatch典型用法1:某一线程在开始运行前等待n个线程执行完毕。将CountDownLatch的计数器初始化为n new CountDownLatch(n) ,每当一个任务线程执行完毕,就将计数器减1 countdownlatch.countDown(),当计数器的值变为0时,在CountDownLatch上 await() 的线程就会被唤醒。一个典型应用场景就是启动一个服务时,主线程需要等待多个组件加载完毕,之后再继续执行。

CountDownLatch典型用法2:实现多个线程开始执行任务的最大并行性。注意是并行性,不是并发,强调的是多个线程在某一时刻同时开始执行。类似于赛跑,将多个线程放到起点,等待发令枪响,然后同时开跑。做法是初始化一个共享的CountDownLatch(1),将其计数器初始化为1,多个线程在开始执行任务前首先 coundownlatch.await(),当主线程调用 countDown() 时,计数器变为0,多个线程同时被唤醒。

CountDownLatch两个小案例: 

案例一:秦帝国统一

enum CountryEnum {
	
	ONE(1,"赵"),TWO(2,"魏"),THREE(3,"韩"),FOUR(4,"齐"),FIVE(5,"楚"),SIX(6,"燕");
	
	private Integer code;
	private String countryName;
	
	public Integer getCode() {
		return code;
	}
	public String getCountryName() {
		return countryName;
	}
	private CountryEnum(Integer code, String countryName) {
		this.code = code;
		this.countryName = countryName;
	}
	
	//返回枚举的元素
	public static CountryEnum getElement(int index){
		CountryEnum[] values = CountryEnum.values();
		for (CountryEnum countryEnum : values) {
			if(index==countryEnum.getCode()){
				return countryEnum;
			}
		}
		
		return null;
	}
	
}

/**
 * 秦国灭掉六国后才能统一华夏:
 * 顺便复习下枚举类
 * @author Administrator
 *
 */
public class CountDownLatchDemo2 {

	public static void main(String[] args) throws Exception {
		CountDownLatch countDownLatch=new CountDownLatch(6);
		for (int i = 1; i <= 6; i++) {
			new Thread(()->{
				System.out.println(Thread.currentThread().getName()+"国,灭亡了");
				countDownLatch.countDown();
				
			},CountryEnum.getElement(i).getCountryName()).start();
		}
		
		countDownLatch.await();
		System.out.println(Thread.currentThread().getName()+"\t秦帝国,一统华夏!!!");

	}

}

运行结果:

赵国,灭亡了
韩国,灭亡了
齐国,灭亡了
楚国,灭亡了
魏国,灭亡了
燕国,灭亡了
main	秦帝国,一统华夏!!!

 

案例二:运动员比赛

/**
 * CountDownLatch:CountDownLatch是通过一个计数器来实现的,计数器的初始值为线程的数量。
 * 每当一个线程完成了自己的任务后,计数器的值就会减1。当计数器值到达0时,
 * 它表示所有的线程已经完成了任务,然后在闭锁上等待的线程就可以恢复执行任务。
 *
 */
public class CountDownLatchDemo {
	
    public static void main(String[] args) throws Exception {

    	CountDownLatch prepareLatch = new CountDownLatch(1);//裁判员先发出准备指令,运动员再准备动作
        CountDownLatch prepareOverLatch = new CountDownLatch(10);//计数器,10个运动员准备完成,才开始比赛

        CountDownLatch runnerRunLatch = new CountDownLatch(1);//比赛要在准备完成之后进行
        CountDownLatch runnerOverLatch = new CountDownLatch(10);//计数器,10个运动员都到达终点,才结束比赛

        System.out.println("选手们进场");

        ExecutorService service = Executors.newCachedThreadPool();

        System.out.println("裁判员发出准备指令");
        //裁判员要先发出准备指令,运动员才开始准备
        prepareLatch.countDown();
        //线程池提交10次任务
        for(int i = 0;i<10;i++) {
            final int j = i;
            service.submit(new Runnable() {
                @Override
                public void run() {
                    System.out.println("运动员"+j+"进行准备...");
                    try {
                    	//裁判先发出准备指令,再准备
                        prepareLatch.await();
                        //准备耗时
                        Thread.sleep((long)(Math.random()*1000));
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    } finally {
                        System.out.println("运动员"+j+"准备完成");
                        //每准备好一个运动员,发指令的计算器减一,直到达到定义的线程数才发指令
                        prepareOverLatch.countDown();
                    }
                    
                    //模拟比赛成绩
                    long time = (long)(Math.random()*1000);
                    try {
                        runnerRunLatch.await();
                        Thread.sleep(time);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    } finally {
                        runnerOverLatch.countDown();
                        System.out.println("经历"+time+"秒,运动员"+j+"到达终点。");
                    }
                }
            });
        }

        prepareOverLatch.await();
        System.out.println("都准备好,裁判员发出开始指令");
        runnerRunLatch.countDown();
        runnerOverLatch.await();
        Thread.sleep(300);
        System.out.println("比赛结束");

        service.shutdown();
    }
}

运行结果:

选手们进场
裁判员发出准备指令
运动员2进行准备...
运动员0进行准备...
运动员3进行准备...
运动员1进行准备...
运动员6进行准备...
运动员7进行准备...
运动员4进行准备...
运动员5进行准备...
运动员8进行准备...
运动员9进行准备...
运动员5准备完成
运动员4准备完成
运动员6准备完成
运动员0准备完成
运动员1准备完成
运动员2准备完成
运动员8准备完成
运动员9准备完成
运动员3准备完成
运动员7准备完成
都准备好,裁判员发出开始指令
经历282秒,运动员6到达终点。
经历525秒,运动员5到达终点。
经历628秒,运动员7到达终点。
经历571秒,运动员1到达终点。
经历596秒,运动员9到达终点。
经历763秒,运动员3到达终点。
经历849秒,运动员0到达终点。
经历890秒,运动员8到达终点。
经历891秒,运动员4到达终点。
经历897秒,运动员2到达终点。
比赛结束

 

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值