Java(1) CountDownLatch的理解与使用

CountDownLatch简介

CountDownLatch是一个并发编程工具类,使用计数器实现,可使一个线程等待其他线程完成各自工作后再继续执行,常用来协调多个线程之间的同步,或者说起到线程之间的通信(而不是互斥)作用。

使用步骤

  1. 初始化 ,指定待完成线程的个数;
    CountDownLatch latch = new CountDownLatch(3);
    
  2. 每个待完成线程执行完成后,调用countDown()将计数器减1;
    latch.countDown();
    
  3. 调用await()方法使等待线程处于阻塞状态,当计数到达0时,所有待完成线程执行完毕,等待线程继续执行;
    latch.await();
    

典型用法及实现

1. 某一线程在开始运行前等待n个线程执行完毕

  • 将CountDownLatch的计数器初始化为n;
  • 每当一个任务线程执行完毕,调用countDown(),计数器减1;
  • 当计数器的值减为0时,在CountDownLatch上await() 的线程被唤醒。

一个典型的应用场景就是老师分发完试卷,等到同学们统一提交后再进行批阅。

import java.util.concurrent.CountDownLatch;

public class CountDownLatch {

   public static void main(String[] args) throws InterruptedException {
   	
   	// 假如一共三个考生
   	CountDownLatch latch = new CountDownLatch(3);

   	// 三个考生分别耗时1,2,3s完成卷子 
   	StudentThread first = new StudentThread(1000, latch, "stu1");
   	StudentThread second = new StudentThread(2000, latch, "stu2");
   	StudentThread third = new StudentThread(3000, latch, "stu3");

   	// 考试铃响,开始发卷
   	long start = System.currentTimeMillis();
   	System.out.println("开始发卷...");
   	first.start();
   	second.start();
   	third.start();

   	// 老师等待所有考生提交试卷
   	latch.await();

   	// 所有考生完成提交试卷
   	System.out.println("所有试卷提交完成!");
   }

   static class StudentThread extends Thread {

   	private int delay;
   	private CountDownLatch latch;

   	public StudentThread(int delay, CountDownLatch latch, String name) {
   		super(name);
   		this.delay = delay;
   		this.latch = latch;
   	}

   	public void run() {
   		try {
   			System.out.println(Thread.currentThread().getName() + "拿到试卷");
   			Thread.sleep(delay);
   			System.out.println(Thread.currentThread().getName() + "提交试卷");
   			// 每提交一份试卷,待提交数减一
   			latch.countDown();
   		} catch (InterruptedException e) {
   			e.printStackTrace();
   		}
   	}
   }
}

输出

开始发卷…
stu1拿到试卷
stu2拿到试卷
stu3拿到试卷
stu1提交试卷
stu2提交试卷
stu3提交试卷
所有试卷提交完成!

可以在代码中调用以下方法来显示各线程的执行时间,帮助理解。

System.currentTimeMillis()

输出

开始发卷…1586868630585
stu1拿到试卷1586868630585
stu2拿到试卷1586868630585
stu3拿到试卷1586868630585
stu1提交试卷1586868631585
stu2提交试卷1586868632586
stu3提交试卷1586868633586
所有试卷提交完成!1586868633587

2. 实现多个线程开始执行任务的最大并行性
这里是并行,不是并发,强调的是多个线程在某一时刻同时开始执行。

  • 初始化一个共享的CountDownLatch(1);
  • 多个线程在开始执行任务前首先调用await();
  • 当主线程调用 countDown() 时,计数器变为0,多个线程同时被唤醒。

一个典型的例子是赛跑,将多个线程放到起点,等待裁判员发令枪响后,多个线程同时开跑。

import java.util.concurrent.CountDownLatch;

public class testLatch {

    public static void main(String[] args) {
        CountDownLatch begin = new CountDownLatch(1);//begin由裁判员发令执行,裁判员countDown,选手await
        CountDownLatch end = new CountDownLatch(2);//end由2个选手完成比赛后执行,选手countDown,裁判员await

        Thread thread1 = new Thread(new Player(begin,end,1000),"选手1");
        // Player1用时1000ms完成比赛
        Thread thread2 = new Thread(new Player(begin,end,1001),"选手2");
        // Player2用时1001ms完成比赛
        thread1.start();    
        thread2.start(); 

        try{
            System.out.println("比赛开始..." + System.currentTimeMillis());            
            
            begin.countDown();//begin由1变为0后,选手起跑
                      
            end.await();//裁判员等待选手完成比赛
            
            System.out.println("比赛结束!" + System.currentTimeMillis());
        }catch(Exception e){
            e.printStackTrace();
        }
    }
}

class Player implements Runnable{

    private CountDownLatch begin;
    private CountDownLatch end;
	private int delay;

    Player(CountDownLatch begin,CountDownLatch end,int delay){
        this.begin = begin;
        this.end = end;
        this.delay = delay;
    }

    public void run() {

        try {
        	begin.await();//选手需等待begin信号
            System.out.println(Thread.currentThread().getName() + "起跑!" + System.currentTimeMillis());
            Thread.sleep(delay);
            System.out.println(Thread.currentThread().getName() + "到达!" + System.currentTimeMillis());
            end.countDown();//countDown()计数减一,当end.getCount()为0时,裁判员线程会自动唤醒,宣告比赛结束

        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

输出

比赛开始…1586869849332
选手1起跑!1586869849334
选手2起跑!1586869849334
选手1到达!1586869850334
选手2到达!1586869850335
比赛结束!1586869850335

感想

纸上得来终觉浅,绝知此事要躬行。希望自己多动手,多动脑,少动嘴,每天吃饱睡好好!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值