并发编程系列(十二)CountDownLatch 闭锁-源码解析

CountDownLatch也叫做闭锁,是一种倒计时计数器。CountDownLatch等待多个线程都执行完成后,再继续做后面的事情。最常见的一个应用场景就是开启多个线程同时执行某个任务,等到所有任务都执行完在统计结果。CountDownLatch内部提供了一个计数器,在构造CountDownLatch时必须执行计数器的初始值,且计数器的初始值必须大于0。另外提供countDown()方法来操作计数器的值,每调用一次CountDown()方法计数器就会减1,直到计数器的值减到0时就代表条件成熟,所有因调用await()方法而阻塞的线程都会被唤醒。 下面我们通过源码来具体分析。
在这里插入图片描述

Sync内部类源码分析
    //Sync继承 AQS使用起state属性来作为count
    private static final class Sync extends AbstractQueuedSynchronizer {
        private static final long serialVersionUID = 4982264981922014374L;
        //构造器
        Sync(int var1) {
            //设置state的值为count
            this.setState(var1);
        }
       //获取count的值,及state的值
        int getCount() {
            return this.getState();
        }
        //重写父类tryAcquireShared的方法
        protected int tryAcquireShared(int var1) {//如果state值为0;返回1否则返回-1
            return this.getState() == 0 ? 1 : -1;
        }
        //重写 父类tryReleaseShared方法
        protected boolean tryReleaseShared(int var1) {
 
             for (;;) {
                //获取state的值
                int c = getState();
                if (c == 0)
                    return false;
                int nextc = c-1;
                //cas更新成功
                if (compareAndSetState(c, nextc))
                    return nextc == 0;
            }
 
        }
    }
CountDownLatch 构造函数
    public CountDownLatch(int count) {
        //构造函数传入的值必须大于0;否则抛出异常
        if (count < 0) throw new IllegalArgumentException("count < 0");
        //创建一个Sync对象
        this.sync = new Sync(count);
    }

await() 方法解析

当前线程调用了await()方法后会,会将当前线程阻塞直到出现下面两种情况之一才会返回:

当所有线程调用都调用了countDown方法后,也就是说调用了await方法的都要在调用countDown方法一遍使计数器的值为0

其他线程调用了当前线程的interrupt方法中断了当前线程, 当前线程会抛出interruptedException异常返回。

    public void await() throws InterruptedException {
        //sync调用父类的acquireSharedInterruptibly方法
        sync.acquireSharedInterruptibly(1);
    }
    public final void acquireSharedInterruptibly(int arg)
            throws InterruptedException {
         //如果线程被中断,则抛出异常
        if (Thread.interrupted())
            throw new InterruptedException();
        //如果tryAcquireShared小于0,则进入AQS同步队列
        if (tryAcquireShared(arg) < 0)
            //调用AQS的方法进入同步队列
            doAcquireSharedInterruptibly(arg);
    }

Sync类的tryAcquireShared方法在state等于0时返回1;否则返回-1

回到AQS的AcquireSharedInterruptibly方法,当Sync类的tryAcquireShared返回1则回到AQS的AcquireSharedInterruptibly方法返回,即await方法返回;

await(long timeout,TimeUnit unit)源码分析
    public boolean await(long timeout, TimeUnit unit)
        throws InterruptedException {
        return sync.tryAcquireSharedNanos(1, unit.toNanos(timeout));
    }

AQS中的tryAcquireSharedNanos方法

    public final boolean tryAcquireSharedNanos(int arg, long nanosTimeout)
            throws InterruptedException {
        if (Thread.interrupted())
            throw new InterruptedException();
        return tryAcquireShared(arg) >= 0 ||
            doAcquireSharedNanos(arg, nanosTimeout);
    }

AQS中的doAcquireSharedNanos方法

    private boolean doAcquireSharedNanos(int arg, long nanosTimeout)
            throws InterruptedException {
        if (nanosTimeout <= 0L)
            return false;
        final long deadline = System.nanoTime() + nanosTimeout;
        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 true;
                    }
                }
                nanosTimeout = deadline - System.nanoTime();
                if (nanosTimeout <= 0L)
                    return false;
                if (shouldParkAfterFailedAcquire(p, node) &&
                    nanosTimeout > spinForTimeoutThreshold)
                    LockSupport.parkNanos(this, nanosTimeout);
                if (Thread.interrupted())
                    throw new InterruptedException();
            }
        } finally {
            if (failed)
                cancelAcquire(node);
        }
    }
countDown()方法

当前线程调用了该方法后会递减计数器的值,递减后如果计数器为0,则会唤醒await方法而被阻塞的线程,否则什么都不做。

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

AQS中的releaseShared方法

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

AQS中的doReleaseShared 方法:

    private void doReleaseShared() {
 
        for (;;) {
            Node h = head;
            if (h != null && h != tail) {
                int ws = h.waitStatus;
                if (ws == Node.SIGNAL) {
                    if (!compareAndSetWaitStatus(h, Node.SIGNAL, 0))
                        continue;            // loop to recheck cases
                    unparkSuccessor(h);
                }
                else if (ws == 0 &&
                         !compareAndSetWaitStatus(h, 0, Node.PROPAGATE))
                    continue;                // loop on failed CAS
            }
            if (h == head)                   // loop if head changed
                break;
        }
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值