CountDownLatch 等待所有线程执行完毕

11 篇文章 0 订阅
7 篇文章 0 订阅

CountDownLatch 等待所有线程执行完毕

CountDownLatch类位于java.util.concurrent包下,利用它可以实现类似计数器的功能。比如有一个任务A,它要等待其他4个任务B执行完毕之后才能执行,此时就可以利用CountDownLatch来实现这种功能了。

CountDownLatch

仅有且必需, 需要有参数的构造方法,

初始化倒数次数

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

//Sync  看到这setState,   就有那感觉是利用CAS无锁算法实现的
Sync(int count) { setState(count); }

重点方法CountDownLatch类中

    /**
     * 将计数器的值进行减一, 一直减到0 如果当前计数等于0,那么什么也不会发生。
     *
     * @author: ZhiHao
     * @date: 2021/6/3
     */
public void countDown() {
        sync.releaseShared(1);
    }
--------------------------------------下面方法调用链---------------------------------------------

// sync.releaseShared(1)
public final boolean releaseShared(int arg) {
        if (tryReleaseShared(arg)) {
            doReleaseShared();
            return true;
        }
        return false;
    }

// tryReleaseShared()
protected boolean tryReleaseShared(int releases) {
            // Decrement count; signal when transition to zero
            for (;;) {
                int c = getState();
                if (c == 0)
                    return false;
                int nextc = c-1;
                if (compareAndSetState(c, nextc))
                    return nextc == 0;
            }
        }

tryReleaseShared 方法可以看出, 并没有使用到releases数据参数, 而且是个循环自旋, 当获取的State值为0时候, 返回false, 跳出自旋, 如果不是0, 则减1, 然后调用底层C方法, 比较并设置State值, (也就是CAS无锁算法设置值), 因为同时有多个线程可能进行减, 如果CAS设置失败的话会继续自旋, 继续获取最新的State值进行减1, 继续设置, 设置成功则跳出自旋,。

// 当前线程进行阻塞, 等待计数器值减到0
public void await() throws InterruptedException {
        sync.acquireSharedInterruptibly(1);
    }
// 有限时间的阻塞, 超过则不在阻塞
public boolean await(long timeout, TimeUnit unit)
        throws InterruptedException {
        return sync.tryAcquireSharedNanos(1, unit.toNanos(timeout));
    }
--------------------------------------下面方法调用链---------------------------------------------
// sync.acquireSharedInterruptibly
public final void acquireSharedInterruptibly(int arg)
            throws InterruptedException {
        if (Thread.interrupted())
            throw new InterruptedException();
        if (tryAcquireShared(arg) < 0)
            doAcquireSharedInterruptibly(arg);
    }

// tryAcquireShared(arg)-CountDownLatch
protected int tryAcquireShared(int acquires) {
            return (getState() == 0) ? 1 : -1;
        }

// AQS.doAcquireSharedInterruptibly 只有State值不等于0, 才会调用
private void doAcquireSharedInterruptibly(int arg)
        throws InterruptedException {
        final Node node = addWaiter(Node.SHARED);
        boolean failed = true;
        try {
            for (;;) {
                final Node p = node.predecessor();
                if (p == head) {
                    int r = tryAcquireShared(arg);
                    if (r >= 0) {
                        setHeadAndPropagate(node, r);
                        p.next = null; // help GC
                        failed = false;
                        return;
                    }
                }
                if (shouldParkAfterFailedAcquire(p, node) &&
                    parkAndCheckInterrupt())
                    throw new InterruptedException();
            }
        } finally {
            if (failed)
                cancelAcquire(node);
        }
    }

从上面可以看出, 进行await方法阻塞的时候, 如果获取到State值==0, 直接就结束了阻塞, 继续后面执行,

如果获取到State值!=0, 则会不断自旋进行阻塞, 并State值==0, 结束阻塞

进行测试

@Test
    public void contextLoadss() throws Exception {
        CountDownLatch countDownLatch = new CountDownLatch(2);
        executor.execute(() -> {
            try {
                System.out.println("执行耗时需要5秒");
                TimeUnit.SECONDS.sleep(5);
                countDownLatch.countDown();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });
        executor.execute(() -> {
            try {
                System.out.println("执行耗时需要8秒");
                TimeUnit.SECONDS.sleep(8);
                countDownLatch.countDown();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });
        executor.execute(() -> {
            try {
                countDownLatch.await();
                System.out.println("我需要等上面2个线程执行完毕才执行");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });
        TimeUnit.SECONDS.sleep(10);
        System.out.println("全部完毕执行");
    }

//--------------------------------------------------------
执行耗时需要5秒
执行耗时需要8秒
我需要等上面2个线程执行完毕才执行
全部完毕执行

1

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

懵懵懂懂程序员

如果节省了你的时间, 请鼓励

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值