美文网首页java学习之路
java大厂面试题整理(三)CountDownLatch、Cyc

java大厂面试题整理(三)CountDownLatch、Cyc

作者: 唯有努力不欺人丶 | 来源:发表于2021-03-17 22:49 被阅读0次

    这三者都是juc(jdk中并发的包)中的概念。简单说

    • CountDownLatch:计数器
    • CyclicBarrier 条件满足器
    • Semaphore 信号灯

    下面一个个仔细的说:

    CountDownLatch

    这个之前我学JUC的时候已经记录过了,这里就当复习了,其实这个可以算是计数器,也可以算是门闩。当门里的人都走了,才可以去锁门!
    下面是一个情景demo:
    屋子里有6个人,用六个线程来表示,而main线程充当锁门的那个人。在没有任何操作的情况下的代码:

    有几个人锁死在屋子里了
    其实这个代码因为没有任何处理所以逻辑比较简单,那就是锁门和出门同时进行,把人锁门里是一个正常事件了,这样肯定是不行的。
    但是!!这个时候不会有小机灵鬼说等一等再锁门吧?比如main线程睡个几秒啥的。表面上看上面的程序是可以正常跑了,但是仔细想想,这几个线程什么时候出门是不固定的啊。万一睡个几小时再出门呢?所以这个方法绝对是不行了。
    这个时候计数器CountDownLatch就要起作用啦!
    这个计数器的用法也很简单,大概的思路就是初始的时候设置倒计数。每次调用countDown()的时候计数器会减一。如果调用了await方法以后,直到计数器数字为0才能往下走。如下代码:
        public static void main(String[] args) {
            CountDownLatch countDownLatch = new CountDownLatch(6);
            for(int i = 0;i<6;i++) {
                new Thread(()-> {                  
                    System.out.println(Thread.currentThread().getName()+"离开了!");
                    countDownLatch.countDown(); 
                },String.valueOf(i)).start();
            }
            try {
                countDownLatch.await();
                System.out.println("锁门了!");
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }   
        }
    

    上面代码的重点其实就两个:一个countDownLatch.countDown(); 一个countDownLatch.await();
    这里要注意一定要把countDownLatch.countDown()放在打印语句下面。不然可能会出现先归零锁门,再输出离开了的打印语句。

    CyclicBarrier

    这个和计数器正好相反,而是一个加法。从0增加到给定值,类似于七颗龙珠召唤神龙一样。同样一个小情景:七个人要开会。人到齐了才能开始。否则就要等人。
    下面依然代码做demo:

        public static void main(String[] args) {
            CyclicBarrier cyclicBarrier = new CyclicBarrier(7,()->{
                System.out.println("人齐了,可以开会了!");
            });     
            for(int i = 0;i<7;i++) {
                new Thread(()-> {                  
                    System.out.println(Thread.currentThread().getName()+"来了!"); 
                    try {
                        cyclicBarrier.await();
                    } catch (Exception e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    } 
                },String.valueOf(i)).start();
            }
        }
    

    这里依然两个小重点:一个是 CyclicBarrier的函数式接口中,写满足条件的逻辑。
    一个是cyclicBarrier.await();方法代表加入这个cyclicBarrier的等待队列。
    当等待数目达到要求,就可以执行满足条件的逻辑代码了。

    Semaphore

    这个是信号灯,是可伸缩可变化的。据说小米的秒杀系统中大量使用这个哟!
    使用场景大概是多个线程抢多个资源。信号灯主要用于两个目的:一个是用于多个共享资源的互斥使用。另一个用于并发线程数的控制。
    Semaphore默认是非公平锁。
    下面一个使用场景是停车位和车。默认初始3个停车位。7个车去抢,现在的代码demo:

        public static void main(String[] args) {
            Semaphore semaphore = new Semaphore(3);
            for(int i = 0;i<7;i++) {
                new Thread(()-> {                  
                    try {
                        semaphore.acquire(); 
                        System.out.println(Thread.currentThread().getName()+"抢到车位了!");
                        TimeUnit.SECONDS.sleep(2);
                        System.out.println(Thread.currentThread().getName()+"离开了!");
                        semaphore.release();
                    } catch (Exception e) {
                        e.printStackTrace();
                    }finally {
                        
                    }
                },String.valueOf(i)).start();
            }
        }
    

    这个信号灯的重点有三个:一个是默认的资源量(初始的时候设置的3).一个是占用资源:semaphore.acquire()。还有一个是释放资源:semaphore.release()。
    这里信号灯牛就牛在不是单一的操作。而是可用可还的那种。
    执行起来结果如下:

    信号灯测试结果
    大家可以注意,同时最多三个车在停车位停着。但是其自动离开释放资源使得7个车最终都停成功了。不同于上面的计数器和cyclicBarrier的单向操作,这个是有借有还的。对于刻在用资源来讲信号灯是很实用的!
    本篇笔记就记到这里,如果稍微帮到你了记得点个喜欢点个关注,也祝大家工作顺顺利利!

    相关文章

      网友评论

        本文标题:java大厂面试题整理(三)CountDownLatch、Cyc

        本文链接:https://www.haomeiwen.com/subject/adhjcltx.html