漫画:Java并发闭锁CountDownLatch

(之前掘金的“程序员七猫”账号找不到了,只好重新开了个,会把前2篇文章都搬家到这里到)


本次漫画改编自鸿洋的《Java 并发专题 :闭锁 CountDownLatch 之一家人一起吃个饭》 https://blog.csdn.net/lmj623565791/article/details/26626391

谢谢鸿洋大神的支持!

某天,小猫咪一家决定要去饭馆吃饭,到了快下班的时候,family·f3群里开始聊起天来

family·f3

以下是来自这位可怜的猫咪爸爸的吐槽

猫咪爸爸到吐槽

下班到了(欢呼!),大家都开始出发去饭店了

public class Test1
{
    /**
     * 模拟爸爸去饭店
     */
    public static void fatherToRes()
    {
        System.out.println("爸爸步行去饭店需要3小时。");
    }
    /**
     * 模拟妈妈去饭店
     */
    public static void motherToRes()
    {
        System.out.println("妈妈挤公交去饭店需要2小时。");
    }
    /**
     * 模拟我去饭店
     */
    public static void meToRes()
    {
        System.out.println("我乘地铁去饭店需要1小时。");
    }
    /**
     * 模拟一家人到齐了
     */
    public static void togetherToEat()
    {
        System.out.println("一家人到齐了,开始吃饭");
    }
    public static void main(String[] args)
    {
        fatherToRes();
        motherToRes();
        meToRes();
        togetherToEat();
    }
}

输出结果

爸爸步行去饭店需要3小时。
妈妈挤公交去饭店需要2小时。
我乘地铁去饭店需要1小时。
一家人到齐了,开始吃饭

!停停停 !是不是哪里不对了,为什么是猫咪爸爸走完3小时,妈妈再去坐公交车2小时,然后才等到小猫咪乘地铁1小时,这整整花了6小时,那还吃什么饭,直接买份夜宵算了!

猫咪爸爸、妈妈、小猫咪都是各自按下班时间出发的,属于并发的,所以我们换个场景

开启爸爸走路、妈妈坐公交、小猫咪坐地铁三个线程,如下

public static void main(String[] args)
    {
        new Thread()
        {
            public void run()
            {
                fatherToRes();
            };
        }.start();
        new Thread()
        {
            public void run()
            {
                motherToRes();
            };
        }.start();
        new Thread()
        {
            public void run()
            {
                meToRes();
            };
        }.start();
        togetherToEat();
    }

输出结果

一家人到齐了,开始吃饭
我乘地铁去饭店需要1小时。
妈妈挤公交去饭店需要2小时。
爸爸步行去饭店需要3小时。

喵?喵?喵?!

开启了线程并发了,但是貌似也不对啊,一家三都还没到饭馆,怎么能先吃起饭来?

于是再换一个方法

private static volatile int i = 3;
    public static void main(String[] args)
    {
        new Thread()
        {
            public void run()
            {
                fatherToRes();
                i--;
            };
        }.start();
        new Thread()
        {
            public void run()
            {
                motherToRes();
                i--;
            };
        }.start();
        new Thread()
        {
            public void run()
            {
                meToRes();
                i--;
            };
        }.start();
        while (i != 0);
        togetherToEat();
    }

关键修饰符volatile

volatile作用:当多个线程操作同一个变量时,用于保证变量修改对于其他线程的可见性。但是volatile不能保证原子性,而i--不是原子操作。所以建议正常使用同步块或者AtomicLong.decrementAndGet()实现--。

马上来~

private static CountDownLatch latch = new CountDownLatch(3);
    public static void main(String[] args) throws InterruptedException
    {
        new Thread()
        {
            public void run()
            {
                fatherToRes();
                latch.countDown();
            };
        }.start();
        new Thread()
        {
            public void run()
            {
                motherToRes();
                latch.countDown();
            };
        }.start();
        new Thread()
        {
            public void run()
            {
                meToRes();
                latch.countDown();
            };
        }.start();
        latch.await();
        togetherToEat();
    }

输出结果

我乘地铁去饭店需要1小时。
妈妈挤公交去饭店需要2小时。
爸爸步行去饭店需要3小时。
一家人到齐了,开始吃饭

CountDowmLatch是一种灵活的闭锁实现,包含一个计数器,该计算器初始化为一个正数,表示需要等待事件的数量。countDown方法递减计数器,表示有一个事件发生,而await方法等待计数器到达0,表示所有需要等待的事情都已经完成,那么就可以继续执行当前线程了。

CountDownLatch的使用场景

1、例如上例中所有人都到达饭店然后吃饭

2、某个操作需要的资源初始化完毕

3、某个服务依赖的线程全部开启等等...

上烤鱼喽~

烤鱼图源来自网络侵权则删

依然感谢支持我的小伙伴们以及网友们~

您的关注与支持是我最大的动力~

本人公众号:程序员七猫

欢迎关注点赞以及提建议

猜你喜欢

转载自juejin.im/post/5af06c4e518825670e5cff4a