• Java 多线程 先批量执行1号任务和部分2号任务,等待1号全部任务完成后,再执行剩下的2号任务内容 - CountDownLatch


    一、CountDownLatch —— 先批量执行1号任务和部分2号任务,等待1号全部任务完成后,再执行剩下的2号任务内容

    利用多线程内的共享内存特性,获取计数值,每次调用countDown方法,就会判断是否为0,如果不是0,就会自动减 1,直到为 0 为止。

    CountDownLatch有一个内部类叫做Sync,它继承了AbstractQueuedSynchronizer类,其中维护了一个整数state,并且保证了修改state的可见性和原子性。(其实就是需要在创建CountDownLatch 实例时,需要传递一个整形 int 的参数,用来当做计数值的初始值,当然这个计数值,肯定不会动态变化的就是

    如下实例化 CountDownLatch 类,传递了 3 这个整形数字,作为计数值,后面就是一个一个的减 1 直到 0 为止。

    CountDownLatch latch = new CountDownLatch(3);
    
    • 1

    具体的 CountDownLatch 类代码解释如下:

    创建CountDownLatch实例时,也会创建一个Sync的实例,同时把计数器的值传给Sync实例,具体是这样的:

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

    countDown方法中,只调用了Sync实例的releaseShared方法,具体是这样的:

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

    其中的releaseShared方法,先对计数器进行减1操作,如果减1后的计数器为0,唤醒被await方法阻塞的所有线程,具体如下的:

    public final boolean releaseShared(int arg) {
        if (tryReleaseShared(arg)) { //对计数器进行减一操作
            doReleaseShared();//如果计数器为0,唤醒被await方法阻塞的所有线程
            return true;
        }
        return false;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    其中的tryReleaseShared方法,先获取当前计数器的值,如果计数器为0时,就直接返回;如果不为0时,使用CAS方法对计数器进行减1操作,具体是这样的:

    protected boolean tryReleaseShared(int releases) {
        for (;;) {//死循环,如果CAS操作失败就会不断继续尝试。
            int c = getState();//获取当前计数器的值。
            if (c == 0)// 计数器为0时,就直接返回。
                return false;
            int nextc = c-1;
            if (compareAndSetState(c, nextc))// 使用CAS方法对计数器进行减1操作
                return nextc == 0;//如果操作成功,返回计数器是否为0
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    await方法中,只调用了Sync实例的acquireSharedInterruptibly方法,具体是这样的:

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

    其中acquireSharedInterruptibly方法,判断计数器是否为0,如果不为0则阻塞当前线程,具体是这样的:

    public final void acquireSharedInterruptibly(int arg)
            throws InterruptedException {
        if (Thread.interrupted())
            throw new InterruptedException();
        if (tryAcquireShared(arg) < 0)//判断计数器是否为0
            doAcquireSharedInterruptibly(arg);//如果不为0则阻塞当前线程
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    其中tryAcquireShared方法,是AbstractQueuedSynchronizer中的一个模板方法,其具体实现在Sync类中,其主要是判断计数器是否为零,如果为零则返回1,如果不为零则返回-1,具体是这样的:

    protected int tryAcquireShared(int acquires) {
        return (getState() == 0) ? 1 : -1;
    }
    
    • 1
    • 2
    • 3

    参考链接

    腾讯面试居然跟我扯了半小时的CountDownLatch

    java 多线程按顺序执行、顺序获取结果

  • 相关阅读:
    武汉工程大学计算机考研资料汇总
    【Web漏洞探索】跨站脚本漏洞
    MySQL LIKE BINARY 和 LIKE 模糊查询
    运行yolov5 v6遇到的问题
    LeetCode 852. 山脉数组的峰顶索引
    餐厅预订APP多少钱一套?餐厅预订APP如何收费?
    推动制造业数字化转型是发展数字经济的重要环节
    Selenium 案例
    如何学习性能测试?
    【23真题】暴涨45分是专业课简单?还是太卷?
  • 原文地址:https://blog.csdn.net/qq_42701659/article/details/133359839