CountDownLatch多任务处理利器

CountDownLatch 是由java并发包提供的一个同步计数器,从字面意义上去理解可以分成两部分CountDown 和 Latch,CountDown就是计数的意思,Latch是门闩,这个同步工具就是通过保证多线程环境下,通过门闩限制主线程执行,子线程执行后计数减1,直到减为0,门闩打开,主线程执行。

场景一:主任务等待其它子任务完成后再执行。

背景:电影院等待所有人都到齐了还开始播放电影,有一个电影院的类为主线程,看电影的人为子线程,假设电影院能容纳5人看电影,下面的类将利用CountDownLatch实现该功能。

public class Cinema {
    public static void main(String[] args) {
        CountDownLatch countDownLatch = new CountDownLatch(5);
        ExecutorService executor = Executors.newFixedThreadPool(3);
        for(int i=0; i<5; i++){
            executor.execute(new Person(countDownLatch));
        }

        System.out.println("电影院等待人入场...");
        //阻塞当前线程,直到计数器的值为0
        try {
            countDownLatch.await();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("人已到齐,开始播放电影...");
    }
}
public class Person implements Runnable{
    private CountDownLatch countDownLatch;
    public Person(CountDownLatch countDownLatch){
        this.countDownLatch = countDownLatch;
    }


    @Override
    public void run() {
        try {
            Thread.sleep((long) (Math.random() * 0));
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(String.format("%s又有观众入场了", Thread.currentThread().getId()));
        countDownLatch.countDown();
        System.out.println(String.format("%s还有%s人未入场", Thread.currentThread().getId(), countDownLatch.getCount()));
    }
}

执行下看结果:

电影院等待人入场...
13又有观众入场了
11又有观众入场了
12又有观众入场了
11还有3人未入场
13还有4人未入场
12还有2人未入场
13又有观众入场了
11又有观众入场了
13还有1人未入场
人已到齐,开始播放电影...
11还有0人未入场

这个时候可以思考一下现实情况,不是任何时候电影院都是满场才放电影的,那么就需要设置一个时间,如果到时间了人还未到齐,就开始播放电影,这个程序怎么写呢。

public class Cinema {
    public static void main(String[] args) {
        CountDownLatch countDownLatch = new CountDownLatch(10);
        ExecutorService executor = Executors.newFixedThreadPool(3);
        for(int i=0; i<5; i++){
            executor.execute(new Person(countDownLatch));
        }

        System.out.println("电影院等待人入场...");
        //阻塞当前线程,直到计数器的值为0
        try {
            countDownLatch.await(300, TimeUnit.MILLISECONDS);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("人已到齐,开始播放电影...");
    }
}

这里用了CountDownLatch的await的另外一个重载方法,并且增加了CountDownLatch的阈值,让人更多一些方便跑数据。看结果:

电影院等待人入场...
12又有观众入场了
13又有观众入场了
13还有8人未入场
12还有9人未入场
11又有观众入场了
11还有7人未入场
12又有观众入场了
12还有6人未入场
13又有观众入场了
13还有5人未入场
人已到齐,开始播放电影...

发现还有5人未到场的时候,电影就开始播放了,是不是很赞。现在大家是不是对CountDownLatch的使用得心应手了,在这里需要提醒的是多线程环境下一定要注意异常,如果发生了异常该如何保证数据一致性,主线程是否要做回滚处理。我们在利用多线程实现性能提升的时候,必然会有线程安全的问题。

你可能感兴趣的:(并发编程)