Jdk1.8版本CountDownLatch实现源码分析

本文详细分析了Jdk1.8中CountDownLatch的使用场景及源码实现。首先介绍了CountDownLatch的基本应用,通过一个实例展示了其等待多个线程完成任务的功能。接着深入探讨了CountDownLatch如何基于AQS的共享模式来实现,特别是利用AQS的state字段作为计数器。文章还提及了内部类Sync的使用。
摘要由CSDN通过智能技术生成
                               

一、CountDownLatch

     

       CountDownLatch的主要应该场景是,可以用来等待其他线程处理完某个任务后再执行主流程,比如,现在我们有一个运算结果依赖于其它几个线程的运行结果,类似这样的场景就可以考虑用CountDownLatch来实现,CountDownLatch是基于AQS实现的,使用了AQS提供的共享模式。

  

二、先看一个使用的简单例子

 

      启动2个子线程,当2个子线程运行结束后,main线程来开始处理。

 public class CountDownLatchExample {

    public static void main(String[] args) {
        final CountDownLatch latch = new CountDownLatch(2);
        new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("第一个子线程运行开始:" + System.currentTimeMillis());
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("第一个子线程运行结束:" + System.currentTimeMillis());
                latch.countDown();
                
            }
        }).start();
        new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("第二个子线程运行开始:" + System.currentTimeMillis());
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("第二个子线程运行结束:" + System.currentTimeMillis());
                latch.countDown();
            }
        }).start();
        try {
            latch.await();
            System.out.println("子线程全部运行结束" + System.currentTimeMillis());
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

     可能的运行效果

    
 第一个子线程运行开始:1506062565771
 第二个子线程运行开始:1506062565779
 第一个子线程运行结束:1506062566772
 第二个子线程运行结束:1506062566779
 子线程全部运行结束1506062566780

      可以看到,当2个子线程跑完后,主线程才开始执行。



三、源码分析


    CountDownLatch使用了AQS里面的原子int域 state来记录Count的数量,采用的是AQS提供的共享模式。


   在CountDownLatch里面,定义了一个Sync内部类

   

 /**
     * Synchronization control For CountDownLatch.
     * Uses AQS state to represent count.
     */
    private static final class Sync extends AbstractQueuedSynchronizer {
        private static final long serialVersionUID = 4982264981922014374L;


        //AQS里面的state用来表示count
        Sync(int count) {
            setState(count);
        }

         
        int getCount() {
            return getState();
        }
        //await的时候, 如果当前count为0,那么方法返回1,  
        //按照之前对AQS的分析,请求成功,并唤醒同步队列里下一个共享模式的线程(这里都是共享模式的)。  
        //如果当前count不为0,那么方法返回-1,请求失败,当前线程最终会被阻塞(之前会不止一次调用tryAcquireShared)。

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

        //释放锁
        protected boolean tryReleaseShared(int releases) {
            // Decrement count; signal when transition to zero
            for (;;) {
                //获取当前内部的int域的值
                int c = getState();
                //如果已经为0,说明已经不用释放了
                if (c == 0)
                    return false;
                //count值-1
                int nextc = c-1;
                //CAS设置最新的值
                if (compareAndSetState(c, nextc))
                   //最后如果count=0了,那么就唤醒所有等待的线程,类比于上面的主线程
                    return nextc == 0;
            }
        }
    }
     CountDownLatch持有Sync的引用

   

//持有静态内部类Sync的引用
    private final Sync sync;

     初始化countDownLatch,可以看到传入的count,最后实际上是对state进行了赋值

   

    /**
     * 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);
    }
      当调用await的时候,表示阻塞主当前线程


  
 /**
     * Causes the current thread to wait until the latch has counted down to
     * zero, unless the thread is {@linkplain Thread#interrupt interrupted}.
     *
     * <p>If the current count is zero then this method returns immediately.
     *
     * <p>If the current count is greater than zero then the current
     * thread becomes disabled for thread scheduling purposes and lies
     * dormant until one of two things happen:
     * <ul>
     * <li>The count reaches zero due to invocations of the
     * {@link #countDown} method; or
     * <li>Some other thread {@linkplain Thread#interrupt interrupts}
     * the current thread.
     * </ul>
     *
     * <p>If the current thread:
     * <ul>
     * <li>has its interrupted status set on entry to this method; or
     * <li>is {@linkplain Thread#interrupt interrupted} while waiting,
     * </ul>
     * then {@link InterruptedException} is thrown and the current thread's
     * interrupted status is cleared.
     *
     * @throws InterruptedException if the current thread is interrupted
     *         while waiting
     */
    public void await() throws InterruptedException {
        //实际会调用AQS里面的方法
          sync.acquireSharedInterruptibly(1);
    }

    /**
     * Causes the current thread to wait until the latch has counted down to
     * zero, unless the thread is {@linkplain Thread#interrupt interrupted},
     * or the specified waiting time elapses.
     *
     * <p>If the current count is zero then this method returns immediately
     * with the value {@code true}.
     *
     * <p>If the current count is greater than zero then the current
     * thread becomes disabled for thread scheduling purposes and lies
     * dormant until one of three things happen:
     * <ul>
     * <li>The count reaches zero due to invocations of the
     * {@link #countDown} method; or
     * <li>Some other thread {@linkplain Thread#interrupt interrupts}
     * the current thread; or
     * <li>The specified waiting time elapses.
     * </ul>
     *
     * <p>If the count reaches zero then the method returns with the
     * value {@code true}.
     *
     * <p>If the current thread:
     * <ul>
     * <li>has its interrupted status set on entry to this method; or
     * <li>is {@linkplain Thread#interrupt interrupted} while waiting,
     * </ul>
     * then {@link InterruptedException} is thrown and the current thread's
     * interrupted status is cleared.
     *
     * <p>If the specified waiting time elapses then the value {@code false}
     * is returned.  If the time is less than or equal to zero, the method
     * will not wait at all.
     *
     * @param timeout the maximum time to wait
     * @param unit the time unit of the {@code timeout} argument
     * @return {@code true} if the count reached zero and {@code false}
     *         if the waiting time elapsed before the count reached zero
     * @throws InterruptedException if the current thread is interrupted
     *         while waiting
     */
   //如果Count=0,那么返回true,如果不为0,会阻塞,直到count=0或者超时或者线程被中断
    public boolean await(long timeout, TimeUnit unit)
        throws InterruptedException {
             //支持超时
            return sync.tryAcquireSharedNanos(1, unit.toNanos(timeout));
    }

      当调用countDown方法时,表示对同步计数器-1

    
    /**
     * Decrements the count of the latch, releasing all waiting threads if
     * the count reaches zero.
     *
     * <p>If the current count is greater than zero then it is decremented.
     * If the new count is zero then all waiting threads are re-enabled for
     * thread scheduling purposes.
     *
     * <p>If the current count equals zero then nothing happens.
     */
   //每次调用counDown的时候,同步计数器-1,最后当count=0时,唤醒所有等待线程,如果Count本身就是0了,那么什么都不做
    public void countDown() {
        sync.releaseShared(1);
    }

     最后,看一下CountDownLatch提供了其它方法,

     

  /**
     * Returns the current count.
     *
     * <p>This method is typically used for debugging and testing purposes.
     *
     * @return the current 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() + "]";
    }
}

     至此,CountDownLatch分析完毕。
 
  
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值