Java并发源码分析CountDownlatch源码

CountDownlatch源码分析

CountDolwnlatch(闭锁)是Java并发包中提供的并发工具之一,可以让多个线程同时等待其他线程完成后在进行下一步操作。具体使用场景以后分析。

先看看简单使用例子

public class Demo {

      private static CountDownLatch countDownLatch=new CountDownLatch(2);

      public static void main(String[] args) {

      new Thread(()->cook()).start(); // 开始煮饭

      new Thread(()->BrushTooth()).start(); //开始刷牙

     try {

      countDownLatch.await();

     } catch (InterruptedException e) {

     e.printStackTrace();

     }

     goSchool();

}

     public static void cook(){

       System.out.println("煮饭30分钟");

       countDownLatch.countDown();

}

    public static void BrushTooth(){

    System.out.println("刷牙10分钟");

    countDownLatch.countDown();

}

    public static void goSchool(){

     System.out.println("去学校");

}

}

 

由例子可知,在Main方法调用await时,如果其他两个线程没有执行完毕countDown(),那么Main会等待完成后继续执行,接下来对源码进行分析。

源码结构如图所示:包括一个同步器,一个构造方法,定时和不定时的await方法,countDown方法,获取getCount方法。

1.构造方法

// 主要创建内部实现Sync
public CountDownLatch(int count) {
    if (count < 0) throw new IllegalArgumentException("count < 0");
    this.sync = new Sync(count);
}
private static final class Sync extends AbstractQueuedSynchronizer {
    Sync(int count) {
        setState(count);// 将AQS中State设置为count值
    }
    int getCount() {
        return getState();
    }
    protected int tryAcquireShared(int acquires) {
        return (getState() == 0) ? 1 : -1;// 当state值为0的时候
    }
    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;
        }
    }
}

由源码可知,构造方法就是new出同步器,然后设置state值。

2.await方法

     此方法主要用于让当前线程等待,直到其他线程调用countDown()到一定数目才唤醒,源码如下:

public void await() throws InterruptedException {
    sync.acquireSharedInterruptibly(1);// 调用AQS acquireSharedInterruptibly 可中断共享
}
// AQS模板方法
public final void acquireSharedInterruptibly(int arg)
        throws InterruptedException {
    if (Thread.interrupted()) //如果线程中断,爆出异常
        throw new InterruptedException();
    if (tryAcquireShared(arg) < 0) // 调用Countdownlatch中syn 实现方法
        doAcquireSharedInterruptibly(arg);
}
protected int tryAcquireShared(int acquires) {
    return (getState() == 0) ? 1 : -1; // 当state不等于0将调用doAcquireSharedInterruptibly()方法
}

      由上述源码可以得出,当如果调用await()时state值已经为0将直接结束,当前线程继续执行。如果不为0将进入AQS源码doAcquireSharedInterruptibly中,这里不对此源码进行分析,后续AQS分析时在继续分析,doAcquireSharedInterruptibly()大概功能会自旋尝试获取到资源,如果获取到了,那么将返回值,然后await方法结束,如例子中是Main线程,将继续执行main方法后面的goSchool(),如果获取不到会被阻塞等待被唤醒。

      await方法流程图,如下所示,其中自旋与阻塞部分由AQS框架实现,这里只简单描述。

                       

3.await定时方法 

此方法与await方法相比不同在于可以设置一个时间,如果在等待了当前时间比如5s后其他线程还没执行完毕,那么不再等待。定时原理留在AQS中分析。

4.countDown方法

public void countDown() {
    sync.releaseShared(1);//用于减少当前state值1
}
public final boolean releaseShared(int arg) {
    if (tryReleaseShared(arg)) { //调用内部实现Syn的方法作为是否唤醒的条件
        doReleaseShared();
        return true;
    }
    return false;
}
protected boolean tryReleaseShared(int releases) {
    for (;;) {
        int c = getState();
        if (c == 0) //state已经为0时再次调用直接返回false,不影响程序
            return false;
        int nextc = c-1;
        if (compareAndSetState(c, nextc)) //CAS更新state值
            return nextc == 0; 
    }
}

countDown方法就是让state值减1。当state为0时,调用AQS中doReleaseShared方法,将阻塞的节点唤醒。

5.小结

countdownlatch就是通过实现AQS,通过state值来控制需等待的线程数。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值