美文网首页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