JUC线程进阶篇03:CountDownLatch闭锁

JUC线程进阶篇03:CountDownLatch闭锁

标签: 多线程

CountDownLatch,直译的意思是:倒计时的闩。专业的称呼是:闭锁。

既然是一个“门闩”,那么在闭锁到达结束状态之前,这个门一直都是关闭的,没有任何线程能够通过;当到达结束状态时,会打开门闩,允许所有线程通过。

CountDownLatch是java5中新增的一个并发工具类。可以使一个或多个线程等待一组事件发生,只有其他所有线程的运算全部完成,当前运算才继续执行。

场景

现在我们在子线程中打印50000以内的所有偶数, 然后在主线程中创建5个这样的子线程,并获取他们的执行时间。

错误的写法

如果我像下面这样写,那肯定是不行的。因为6个线程同时并发执行,怎么能计算呢?

public class TestCountDownLatch {
    public static void main(String[] args) {
        LatchDemo ld = new LatchDemo();
        long start = System.currentTimeMillis();

        for (int i = 0 ; i < 5 ; i++) {
            new Thread(ld).start();
        }

        long end = System.currentTimeMillis();
        System.out.println("所用时间:" + (start-end));
    }
}

class LatchDemo implements Runnable{
    public void run() {
        for (int i = 0 ; i < 50000 ; i++) {
            if (i % 2 == 0) {
                System.out.println(i);
            }
        }
    }
}

正确的写法

分析

对于需求,我们希望的是在5个子线程执行完成之后,再获取时间。这就需要一个先后顺序。CountDownLatch直译是倒计时的闩,我们使用CountDownLatch来实现一个计数器,执行一个线程,计数器递减1,直到计数器变为0。在计数器变为0之前,我们用一个“闩”阻塞主程序,直到变为0,主程序才继续执行。

那么对应到代码上,使用CountDownLatch的构造函数接收一个int类型的参数作为计数器:

final CountDownLatch latch = new CountDownLatch(5);

CountDownLatch的方法调用countDown()来递减计数器。这个是一定要执行的,所以最好放在finally中。

latch.countDown();

使用await()方法阻塞主线程,直到计数器为0

latch.await();

代码

import java.util.concurrent.CountDownLatch;

public class TestCountDownLatch {
    public static void main(String[] args) {
        // 1. 创建一个闭锁,并设置计时器
        final CountDownLatch latch = new CountDownLatch(5);
        // 2. 将闭锁作为参数,传递到子线程中
        LatchDemo ld = new LatchDemo(latch);
        long start = System.currentTimeMillis();

        for (int i = 0 ; i < 5 ; i++) {
            new Thread(ld).start();
        }

        try {
            // 5. 等待计时器归零,才执行下面的语句
            latch.await();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        long end = System.currentTimeMillis();
        System.out.println("所用时间:" + (end-start));
    }
}

class LatchDemo implements Runnable{

    private CountDownLatch latch;

    // 3. 子线程需要传入一个闭锁
    public LatchDemo (CountDownLatch latch) {
        this.latch = latch;
    }

    public void run() {
        synchronized (this) {
            try {
                for (int i = 0; i < 50000; i++) {
                    if (i % 2 == 0) {
                        System.out.println(i);
                    }
                }
            } finally {
                // 4. 计时器减1
                latch.countDown();
            }
        }
    }
}

CountDownLatch与join的区别

调用thread.join() 方法必须等thread执行完毕,当前线程才能继续往下执行,而CountDownLatch通过计数器提供了更灵活的控制,只要检测到计数器为0当前线程就可以往下执行而不用管相应的thread是否执行完毕。

    原文作者:JUC
    原文地址: https://blog.csdn.net/japson_iot/article/details/80043186
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞