Java并发编程-CountDownLatch

一、 应用场景html

  CountDownLatch是并发包中用来控制一个或者多个线程等待其余线程完成操做的并发工具类。现以工做中的一个场景来描述下CountDownLatch的应用,代码以下:算法

 

/*模拟工做中的一个需求场景:
用户会选择多个算法来计算费用,最后会将全部算法计算出的费用作一个加权求平均数,这个平均数是最终的费用。
每一个算法的复杂度都不同,打算每一个线程负责一个算法的实现,全部的线程执行完成,最后再求平均数。
一、为每一个算法建立一个线程,每一个线程负责一个算法的实现
二、经过CountDownLatch来控制全部算法线程的同步
三、所有计算完成后再求平均数 */public class CountDownLatchTask {    public static void main(String[] args) {
        CountDownLatchTask countDownLatchTask = new CountDownLatchTask();
        countDownLatchTask.startThreads(5);
    }    //根据线程数和选择的算法 调度算法对应的实现
    private void startThreads(int threadNumber) {
        CountDownLatch countDownLatch = new CountDownLatch(threadNumber);        for (int i = 0; i < threadNumber; i++) {            new Thread(new Runnable() {
                @Override                public void run() {
                    System.out.println("线程算法实现:" + Thread.currentThread().getName());
                    countDownLatch.countDown();
                }
            }).start();
        }        try {
            countDownLatch.await();
            System.out.println("加权求平均数");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

 

  在分析原理实现前,总结下CountDownLatch的做用就是阻塞其余线程直到条件容许后才释放该阻塞,除了上述这个小案例,实际工做中还有不少可使用CountDownLatch的场景,好比解析Excel文件时能够同时解析多个Sheet页,全部的Sheet解析完成才算完成了Excel文件的解析。从这个代码中也能够看到CountDownLatch的主要方法就是await和countDown,下面将以这两个方法来分析下CountDownLatch的原理实现。并发

 二、 源码原理解析ide

 2.1 await方法工具

  调用await方法会阻塞当前线程直到计数器的数值为0,方法以下:学习

public void await() throws InterruptedException {
        sync.acquireSharedInterruptibly(1); //共享式获取AQS的同步状态}

  调用的是AQS的acquireSharedInterruptibly方法:ui

 

public final void acquireSharedInterruptibly(int arg)            throws InterruptedException {        if (Thread.interrupted())//线程中断 说明闭锁对线程中断敏感
            throw new InterruptedException();        if (tryAcquireShared(arg) < 0) //闭锁未使用完成 线程进入同步队列自旋等待             doAcquireSharedInterruptibly(arg);
    }

 

  其中tryAcquireShared依赖的是Sync的实现,和以前的ReentrantLockReentrantReadWriteLockSemaphore相比,CountDownLatch的Sync只提供了一种方式,代码以下:线程

protected int tryAcquireShared(int acquires) {            return (getState() == 0) ? 1 : -1; //AQS的同步状态为0则闭锁结束 能够进行下一步操做
        }

  doAcquireSharedInterruptibly方法就再也不赘述,和以前Semaphore的实现是一致的,本质上仍然是AQS同步队列的入队自旋等待。htm

2.2 countDown方法blog

  调用countDown方法会将计数器的数值减1直到计数器为0,方法以下:

public void countDown() {
        sync.releaseShared(1);
    }

  和Semaphore同样,调用的是AQS的releaseShared方法:

 

public final boolean releaseShared(int arg) {        if (tryReleaseShared(arg)) {//减小闭锁的计数器
            doReleaseShared();//唤醒后续线程节点
           return true;
        }        return false;
    }

 

  其中tryReleaseShared依赖的是Sync的实现,和以前的ReentrantLockReentrantReadWriteLockSemaphore相比,CountDownLatch的Sync只提供了一种方式,代码以下:

 

protected boolean tryReleaseShared(int releases) {            // Decrement count; signal when transition to zero
            for (;;) {                int c = getState();                if (c == 0)                    return false; //计数器已是0了
                int nextc = c-1; //计数器减1
                if (compareAndSetState(c, nextc)) //CAS更新同步状态
                    return nextc == 0;
                    加群:874811168 一块儿学习,一块儿进步
                    进群便可免费领取资料一份
            }
        }

 

  唤醒后续线程节点的doReleaseShared也再也不赘述,和以前Semaphore的实现是一致的。

  总结:CountDownLatch类使用AQS同步状态来表示计数。在await时,全部的线程进入同步队列自旋等待,在countDown时,获取闭锁成功的线程会减小闭锁的计数器,同时唤醒后续线程取获取闭锁,直到await中的计数器为0,获取到闭锁的线程才能够经过,执行下一步操做。

        出处:https://www.cnblogs.com/iou123lg/p/9739697.html

相关文章
相关标签/搜索