Jdk1.6 JUC源码解析(9)-CountDownLatch

Jdk1.6 JUC源码解析(9)-CountDownLatch

作者:大飞

 

功能简介:

  • CountDownLatch是一种锁,称为闭锁。可以让一个或多个线程等待另外一个或多个线程执行完毕后再执行。
  • CountDownLatch也是基于AQS构建,使用共享模式。
  • CountDownLatch中提供一个count值来表示要等待的(其他任务)完成次数,常规用法有两种:Count(1)和Count(N)。举个栗子,百米赛跑,N个选手,每个选手可以看成是一个线程。起跑前,选手准备(线程启动,然后在Count(1)上阻塞),当发令枪响后(相当于Count(1)闭锁释放),选手一起起跑(相当于线程通过Count(1)继续执行),当所有选手都通过终点(相当于Count(N)闭锁释放),然后再统计成绩。

源码分析:

  • CountDownLatch基于AQS构建,首先看下内部的同步器:
    /**
     * CountDownLatch内部同步器,利用AQS的state来表示count。
     */
    private static final class Sync extends AbstractQueuedSynchronizer {
        private static final long serialVersionUID = 4982264981922014374L;
        Sync(int count) {
            setState(count);
        }
        int getCount() {
            return getState();
        }

        protected int tryAcquireShared(int acquires) {
            //如果当前count为0,那么方法返回1,
            //按照之前对AQS的分析,请求成功,并唤醒同步队列里下一个共享模式的线程(这里都是共享模式的)。
            //如果当前count不为0,那么方法返回-1,请求失败,当前线程最终会被阻塞(之前会不止一次调用tryAcquireShared)。
            return getState() == 0? 1 : -1;
        }
        protected boolean tryReleaseShared(int releases) {
            // 如果count为0,返回false,相当于释放失败,因为此时闭锁处于开放状态,没有必要在打开。
            // 如果count不为0,递减count。
            // 最后如果count为0,说明关闭的闭锁打开了,那么返回true,后面会唤醒等待队列中的线程。
            // 如果count不为0,说明闭锁还是处于关闭状态,返回false。
            for (;;) {
                int c = getState();
                if (c == 0)
                    return false;
                int nextc = c-1;
                if (compareAndSetState(c, nextc))
                    return nextc == 0;
            }
        }
    }

 

  • 内部的实现也很简单了: 
public class CountDownLatch {
    private final Sync sync;
    
    ...
    /**
     * 根据给定的count创建一个CountDownLatch。
     */
    public CountDownLatch(int count) {
        if (count < 0) throw new IllegalArgumentException("count < 0");
        this.sync = new Sync(count);
    }
    /**
     * 如果当前count为0,那么方法立即返回。
     *
     * 如果当前count不为0,那么当前线程会一直等待,直到count被(其他线程)减到0或者当前线程被中断。
     */
    public void await() throws InterruptedException {
        sync.acquireSharedInterruptibly(1);
    }
    /**
     * 如果当前count为0,那么方法立即返回true。
     *
     * 如果当前count不为0,那么当前线程会一直等待,直到count被(其他线程)减到0或者当前线程被中断或者超时。
     * 成功返回true,超时返回false,被中断抛异常。
     */
    public boolean await(long timeout, TimeUnit unit)
        throws InterruptedException {
        return sync.tryAcquireSharedNanos(1, unit.toNanos(timeout));
    }
    /**
     * 如果当前count大于0,递减count。如果递减后,count等于0,那么AQS中所有等待线程都被唤醒。
     *
     * 如果当前count等于0,什么事都不会发生。
     */
    public void countDown() {
        sync.releaseShared(1);
    }
    /**
     * 获取当前count值。
     */
    public long getCount() {
        return sync.getCount();
    }
    /**
     * Returns a string identifying this latch, as well as its state.
     * The state, in brackets, includes the String {@code "Count ="}
     * followed by the current count.
     *
     * @return a string identifying this latch, as well as its state
     */
    public String toString() {
        return super.toString() + "[Count = " + sync.getCount() + "]";
    }
}

 

       小总结一下:

              1.建立一个count为n的闭锁后,闭锁的内部计数为n,这时如果有线程调用闭锁的await方法,会阻塞。
              2.每一次调用闭锁的countDown方法,内部计数就会减1,当闭锁的countDown方法被调用n次后,内部计数减为0,这时在闭锁await方法上等待的线程就被唤醒了。  

       CountDownLatch的代码解析完毕!

 

 

       参见:Jdk1.6 JUC源码解析(6)-locks-AbstractQueuedSynchronizer

 

 

    原文作者:JUC
    原文地址: https://blog.csdn.net/iteye_11160/article/details/82642373
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞