面试阿里,现场源码分析CountDownLatch,面试官被我折服,offer到手

面试官:小伙砸,听说你熟读JUC源码啊,今天来考考你CountDownLatch(心想:哼哼,必须难倒这小子,不能让他活着离开)

我:好的,没问题。(哼哼,想难住我,让您老失望了)

面试官:请开始你的表演

我:。。。

 一、CountDownLatch重要方法

// 构造函数,count代表计数器个数(内部是共享锁,本质就是上了几次锁)
一、public CountDownLatch(int count)

// 每countDown一次,计数器就减一,就是释放了一次共享锁,直到为0全部结束
二、public void countDown()

// 在AQS队列里一直等待,直到countDown减到0,才会继续往下执行
三、public void await()

二、重要的内部类Sync

// 继承了AQS
private static final class Sync extends AbstractQueuedSynchronizer {
        private static final long serialVersionUID = 4982264981922014374L;

        Sync(int count) {
            setState(count);
        }

        int getCount() {
            return getState();
        }

        // await判断共享锁是否全部释放,是则从队列中移除,继续往下执行,实现AQS的模板方法
        protected int tryAcquireShared(int acquires) {
            // 判断state同步锁状态是否全部释放
            // 全部释放就可以继续执行被await的代码了
            return (getState() == 0) ? 1 : -1;
        }

        // countDown释放共享锁,实现AQS的模板方法
        protected boolean tryReleaseShared(int releases) {
            // Decrement count; signal when transition to zero
            for (;;) { // 自旋不断判断是否释放了state同步锁
                int c = getState();
                // 如果一进for循环state就是0,说明之前已经释放了同步锁,
                // 这时候就不需要做任何操作了,因为之前已经做完了
                if (c == 0) 
                    return false;
                // state - 1释放一次同步锁
                int nextc = c-1;
                // 通过CAS设置state同步状态,如果成功判断state是否为0,为0代表锁全部释放
                // 被await的程序可以继续往下执行了
                if (compareAndSetState(c, nextc))
                    return nextc == 0;
            }
        }
    }

三、案例举例

示例仍然使用开会案例。老板进入会议室等待5个人全部到达会议室才会开会。所以这里有两个线程老板等待开会线程、员工到达会议室:

public class CountDownLatchTest {
    private static CountDownLatch countDownLatch = new CountDownLatch(5);

    /**
     * Boss线程,等待员工到达开会
     */
    static class BossThread extends Thread{
        @Override
        public void run() {
            System.out.println("Boss在会议室等待,总共有" + countDownLatch.getCount() + "个人开会...");
            try {
                //Boss等待
                countDownLatch.await();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            System.out.println("所有人都已经到齐了,开会吧...");
        }
    }

    //员工到达会议室
    static class EmpleoyeeThread  extends Thread{
        @Override
        public void run() {
            System.out.println(Thread.currentThread().getName() + ",到达会议室....");
            //员工到达会议室 count - 1
            countDownLatch.countDown();
        }
    }

    public static void main(String[] args){
        //Boss线程启动
        new BossThread().start();

        for(int i = 0,j = countDownLatch.getCount() ; i < j ; i++){
            new EmpleoyeeThread().start();
        }
    }
}

四、CountDownLatch构造方法(AQS不懂请看这篇文章https://blog.csdn.net/hnjsjsac/article/details/106520660

创建CountDownLatch时通过此构造方法传入需要上共享锁几次,通过sync这个对象操作AQS的state同步锁状态

    public CountDownLatch(int count) {
        if (count < 0) throw new IllegalArgumentException("count < 0");
        this.sync = new Sync(count);
    }

五、countDown方法(AQS不懂请看这篇文章https://blog.csdn.net/hnjsjsac/article/details/106520660

调用sync.releaseShared,其实是调用AQS里的releaseShared,sync只是去实现了AQS里的tryReleaseShared,去自己控制如何释放state同步锁状态

    public void countDown() {
        sync.releaseShared(1);
    }

六、await方法(AQS不懂请看这篇文章https://blog.csdn.net/hnjsjsac/article/details/106520660

sync.acquireSharedInterruptibly也是调用AQS的acquireSharedInterruptibly方法。sync只是实现了tryAcquireShared,去判断state是否为0,是否释放了同步锁

    public void await() throws InterruptedException {
        sync.acquireSharedInterruptibly(1);
    }

七、总结

1、有了分析AQS的基础后,再来分析CountDownLatch便快了很多;
   其实CountDownLatch就是利用了AQS的共享锁来实现的这些功能
   理解了AQS的共享锁,也就理解了CountDownLatch

2、在这里我简要总结一下CountDownLatch的流程的一些特性:
    • 管理一个大于零的计数器值;
    • 每countDown一次则state就减1一次,直到许可证数量等于0则释放队列中所有的等待线程

面试官脸色铁青:唉,没难住这小子, 只能把offer发给他了

我: offer到手,天下我有

 

关注微信公众号:IT老哥

回复Java全套教程,即可领取:Java基础、Java web、JavaEE全部的教程,包括spring boot等

回复:简历模板,即可获取100份精美简历

回复:Java学习路线,即可获取最新最全的一份学习路线图

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值