Java并发(9)——CountDownLatch

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档


作用

使线程A等待其他线程各自执行完毕后再执行,类似 Thread.join()。

举例:孙悟空收集七龙珠召唤神龙,如果孙悟空串行收集,会浪费太多时间。孙悟空 找了7个帮手,让他们去收集七龙珠。等到7个帮手全部收集完毕之后,孙悟空再召唤神龙。

使用

用法:线程A 调用CountDownLatch.await()开始阻塞等待,当所有执行线程都执行完毕并且都调用CountDownLatch.countDwon(),线程A被唤醒继续执行。

声明CountDownLatch需要指定当前线程等待线程的个数

		
final CountDownLatch countDownLatch = new CountDownLatch(2);

        new Thread(new Runnable(){
            @Override
            public void run() {
                System.out.println("T1 开始执行");
                try {
                    countDownLatch.await();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("T1 执行完成");
            }
        },"Thread1").start();

        new Thread(new Runnable(){
            @Override
            public void run() {

                try {
                    System.out.println("T2 开始执行");
                    Thread.sleep(5000);
                    countDownLatch.countDown();
                    System.out.println("T2 执行完毕");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

            }
        },"Thread2").start();

        new Thread(new Runnable(){
            @Override
            public void run() {
                try {
                    System.out.println("T3 开始执行");
                    Thread.sleep(4000);
                    countDownLatch.countDown();
                    System.out.println("T3 执行完毕");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        },"Thread3").start();
执行结果如下:
T1 开始执行
T2 开始执行
T3 开始执行
T3 执行完毕
T2 执行完毕
T1 执行完成

设计思路

基于aqs
(0)共享模式,即等待线程可以有多个
(1)使用state表示当前正在执行的线程数量,每当一个线程执行完毕,就将state-1。一旦state=0,就会唤醒所有的等待线程。
(2)重写了AQS中tryAcquireShared()、tryReleaseShared(),根据CountDownLatch自身特性重新定义了竞争锁的策略

自身特性如下:
所有执行线程执行完毕 state=0

(3)所有等待线程之间以共享结点的方式进行阻塞,要唤醒就全部会被唤醒。

源码分析

CountDownLatch 初始化

对AQS中的state进行了初始化,表示被等待线程的数量

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

根据自身特性重写方法

state=0 说明所有执行线程执行完毕

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

cas对state进行-1操作,表示一个线程执行完毕

protected boolean tryReleaseShared(int releases) {
            for (;;) {
                int c = getState();
                if (c == 0)
                    return false;
                int nextc = c-1;
                if (compareAndSetState(c, nextc))
                    return nextc == 0;
            }
        }
    }

等待线程调用 await()

由于CountDownLatch自身实现了竞争锁逻辑,当前线程A发现state>0,说明执行线程还没有执行完毕,此时线程A阻塞。

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

state<0 说明此时还有线程未执行完毕,所以当前线程应该进行等待

    public final void acquireSharedInterruptibly(int arg)
            throws InterruptedException {
        if (Thread.interrupted())
            throw new InterruptedException();
        if (tryAcquireShared(arg) < 0)
            doAcquireSharedInterruptibly(arg);
    }

执行线程执行完毕后,调用countDown()
由于CountDownLatch自身实现了释放锁逻辑,当前线程A发现state=0,说明执行线程全部执行完毕,此时线程A唤醒所有阻塞线程。

    public void countDown() {
        sync.releaseShared(1);
    }
    public final boolean releaseShared(int arg) {
        if (tryReleaseShared(arg)) {
            doReleaseShared();
            return true;
        }
        return false;
    }
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值