CountDownLatch源码分析

Posted 叶长风

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了CountDownLatch源码分析相关的知识,希望对你有一定的参考价值。

CountDownLatch源码分析

上一节讲到CopyOnWriteArrayList,其中用到了CountDownLatch,于是想这节就直接讲讲CountDownLatch的原理吧,顺便说下CountDownLatch的简单用法。

CountDownLatch用法


想来想去还是把上一个demo贴过来吧,如下:

CopyOnWriteArrayList<Integer> list = new CopyOnWriteArrayList<>();
        ExecutorService executorService = Executors.newFixedThreadPool(10);
        CountDownLatch countDownLatch = new CountDownLatch(9);
        for (int i = 0; i < 9; i++) 
            executorService.execute(() -> 
                Random random = new Random(System.currentTimeMillis());
                list.add(random.nextInt());
                countDownLatch.countDown();
            );
        
        countDownLatch.await();
        executorService.shutdown();
        System.out.println(list.toString());

这里CountDownLatch会阻塞住executorService的shutdown操作,只有等线程池中的线程运行结束了,这里await方法才会放开限制,继续向下执行。

从这,初步开来,CountDownLatch就是初始化一个count值,countDown方法就是count方法减一操作,await方法即是监听count值为0时,则放开当前方法限制,今日下一步操作,那么这里的count变量应该就是一个cas的操作,否则会受到并发导致count值计算不准确的问题,下面就来看下CountDownLatch的具体源码。

CountDownLatch源码


CountDownLatch对象的初始化为:

CountDownLatch countDownLatch = new CountDownLatch(9);

进入CountDownLatch的构造方法。

 /**
     * Constructs a @code CountDownLatch initialized with the given count.
     *
     * @param count the number of times @link #countDown must be invoked
     *        before threads can pass through @link #await
     * @throws IllegalArgumentException if @code count is negative
     */
    public CountDownLatch(int count) 
        if (count < 0) throw new IllegalArgumentException("count < 0");
        this.sync = new Sync(count);
    

Sync(int count) 
            setState(count);


protected final void setState(int newState) 
        state = newState;

这里的操作比较简单,和之前猜想的相同,对state进行赋值。

我们继续看countDown方法。

public void countDown() 
        sync.releaseShared(1);
    
public final boolean releaseShared(int arg) 
        if (tryReleaseShared(arg)) 
            doReleaseShared();
            return true;
        
        return false;
    

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;
            
        
    

countDwon主要功能方法为tryReleaseShared,这个方法主要功能就是不断获取当前state值,如果当前值为0,则直接返回false,这个情况应该就是几个线程在达到count值时其他线程的情况。

int c = getState();
 if (c == 0)
      return false;

然后此处最后一个到达的线程的操作就是对当前值减一后,cas操作,然后判断nextc值是否为0,如果为0,则返回true.

if (compareAndSetState(c, nextc))
       return nextc == 0;

这里返回true,就回到了releaseShared方法。

if (tryReleaseShared(arg)) 
            doReleaseShared();
            return true;
        

此处进入doReleaseShared方法,这个方法涉及到AQS的共享锁模式,这个在后面单独讲AQS的时候进行讲述,在这就不讲了。

继续看CountDownLatch的源码方法,在countDown方法看完之后,我们继续看await方法,如下:

public void await() throws InterruptedException 
        sync.acquireSharedInterruptibly(1);
    
public final void acquireSharedInterruptibly(int arg)
            throws InterruptedException 
        if (Thread.interrupted())
            throw new InterruptedException();
        if (tryAcquireShared(arg) < 0)
            doAcquireSharedInterruptibly(arg);
    
protected int tryAcquireShared(int acquires) 
            return (getState() == 0) ? 1 : -1;

此处对state值进行判断,state为0,返回1,非0返回-1,在线程没有结束时,进入到doAcquireSharedInterruptibly方法中,这个方法用途就是阻塞当前线程,对state值进行判断,如果值大于1,即所有线程都工作完成后,进行一系列清理操作,最终返回,然后CountDownLatch的工作就完成了。

CountDownLatch的源码还是比较简单的,不过其核心知识点应该在AQS中,这块在最后进行讲述。

以上是关于CountDownLatch源码分析的主要内容,如果未能解决你的问题,请参考以下文章

AQS源码探究_07 CountDownLatch源码分析

AQS源码探究_07 CountDownLatch源码分析

JDK源码分析深入源码分析CountDownLatch

CountDownLatch源码分析

源码分析-CountDownLatch

CountDownLatch源码分析