CountDownLatch应用

 
一、应用场景
 1)主线程开启n个线程后,等待所有子线程执行完成以后,主线程对子线程的数据进行汇总,然后主线程结束即(简单说:主线程等待所有子线程执行完成后,主线程才结束)
 2)2组线程,第一组线程等待第二组线程执行完成以后才执行,即第一组线程wait,第二组线程计数器不断减少
 
二、使用示例
 
package com.test.lock;


import org.slf4j.Logger;
import org.slf4j.LoggerFactory;


import java.util.Random;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;


/**
* 主要用途:
*/


public class CountDownLatchTest4 {
    static Logger logger = LoggerFactory.getLogger(CountDownLatchTest4.class ) ;
    static final int paralNum=10;


    public static int getRandom(){
        Random random = new Random() ;
        int rid = random.nextInt(6);
        System.out.println(String.format("生成随机数:%d", rid+2 ));
        return rid+2;
    }


    public static void main(String[] args) throws InterruptedException {




        AtomicInteger tj = new AtomicInteger();


        CountDownLatch countDownLatch = new CountDownLatch(paralNum);
//        CyclicBarrier cyclicBarrier = new CyclicBarrier(3);


//        for (int i = 1; i <=2 ; i++) {
//            new Thread(()->{
//                try {
//                    countDownLatch.await();
//                } catch (InterruptedException e) {
//                    e.printStackTrace();
//                }
//                logger.info(String.format("t %s 执行结束", Thread.currentThread().getName()));
//
//            },"t"+(i+20)).start(); ;
//        }


        for (int i = 1; i <=paralNum ; i++) {
              new Thread(()->{
                try {
                    TimeUnit.SECONDS.sleep(getRandom());
                    tj.incrementAndGet();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }


                countDownLatch.countDown();
              logger.info(String.format("t %s 执行结束", Thread.currentThread().getName()));


            },"t"+i).start(); ;
        }
        
        System.out.println("主线程结束执行等待");
        countDownLatch.await();
        System.out.println(String.format("主线程结束,汇总值为:%d", tj.get() )) ;
    }
}

 

三、源码主要方法解析
     
            从整体上看:主要是使用AQS框架,初始化的时候给Status一个值,每次countDownLatch.countDown的时候将状态值减一,当status值为0的时候唤醒所有队列上等待的线程。
 
1) 代码1,初始化对象
public CountDownLatch(int count) {
    if (count < 0) throw new IllegalArgumentException("count < 0");
    //status状态赋一个整数值
    this.sync = new Sync(count);
}

 2)方法2,线程等待方法

 

//线程等待
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)// 如果状态==0,则不执行下面等待方法,如果status>0 则会执行下面等待方法
              //线程入队等待
        doAcquireSharedInterruptibly(arg);
}

 

 3)方法3,线程阻塞--到这为止,线程就完成了阻塞,当线程阻塞结束,线程会从这个位置继续执行

   

private void doAcquireSharedInterruptibly(int arg)
    throws InterruptedException {
    //当前线程构建一个node,然后放入到队列中
    final Node node = addWaiter(Node.SHARED);
    boolean failed = true;
    try {
        for (;;) {
            //获取当前节点的前一个节点
            final Node p = node.predecessor();
             //如果前一个节点是头节点
            if (p == head) {
                //判断status是否为==0,如果为0则线程不会阻塞,并且会唤醒前面所有等待的线程
                int r = tryAcquireShared(arg);
                if (r >= 0) {
                    //唤醒前面等待的所有线程
                    setHeadAndPropagate(node, r);
                    p.next = null; // help GC
                    failed = false;
                    return;
                }
            }
            if (shouldParkAfterFailedAcquire(p, node) &&
                //阻塞线程
                parkAndCheckInterrupt())
                throw new InterruptedException();
        }
    } finally {
        if (failed)
            cancelAcquire(node);
    }
}

 

  4)线程状态释放的方法

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;
        //状态 -1
        int nextc = c-1;
        //状态回写
        if (compareAndSetState(c, nextc))
            //如果状态结果 =0,则返回true( 方法会唤醒所有等待的线程)  ,否则false
            return nextc == 0;
    }
}

 

 

 

 

 

posted @ 2020-09-26 18:12  码来  阅读(181)  评论(0编辑  收藏  举报