澳门网络娱乐游戏平台-澳门电子游戏娱乐网址-官方直营

高并发编制程序-CountDownLatch深刻剖判

方法解析

1.构造主意
CountDownLatch(int count卡塔尔(قطر‎布局二个点名计数的CountDownLatch,count为线程将在等待的操作数。

2.await()
高并发编制程序-CountDownLatch深刻剖判。调用await方法后,使当前线程在锁存器(内部流速计卡塔尔国倒计数至零早前一贯等待,步入休眠状态,除非线程被暂停。假诺当前计数依次减少为零,则此方法立时回去,继续奉行。

3.await(long timeout, TimeUnit unit)
调用await方法后,使近来线程在锁存器(内部流速計卡塔尔国倒计数至零在此之前向来等待,进入休眠状态,除非线程被 中断或高于了点名的等候时间。倘若当前计数为零,则此办法立即回去true值。

3.acountDown()
acountDown方法依次减少锁存器的计数,借使计数达到零,则释放具有等待的线程。借使当前计数超过零,则将计数裁减。假设新的计数为零,出于线程调整目标,将再也启用全体的等候线程。

4.getCount()
调用此措施后,重临当前计数,即尚未产生的操作数,此方法常常用于调节和测量试验和测量试验。

总结

面试考场

CountDownLatch和CyclicBarrier的异同?

相似点:都足以兑现线程间的守候。
不同点:
1.侧至关主要区别,CountDownLatch平时用来三个线程等待大器晚成组别的线程;而CyclicBarrier日常是生机勃勃组线程间的互相等待至某同步点;
2.CyclicBarrier的计数器是能够征引的,而CountDownLatch不可能。

澳门官网网址 1

countDown()

CountDownLatch提供countDown()方法依次减少锁存器的计数,假如计数达到零,则释放具有等待的线程。

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

内部调用AQS的releaseShared(int arg卡塔尔(قطر‎方法来刑满释放解除劳教分享锁同步状态:

    public final boolean releaseShared(int arg) {
        if (tryReleaseShared(arg)) {
            doReleaseShared();
            return true;
        }
        return false;
    }

tryReleaseShared(int arg卡塔尔(قطر‎方法被CountDownLatch的里边类Sync重写:

    protected boolean tryReleaseShared(int releases) {
        for (;;) {
            //获取锁状态
            int c = getState();
            //c == 0 直接返回,释放锁成功
            if (c == 0)
                return false;
            //计算新“锁计数器”
            int nextc = c-1;
            //更新锁状态(计数器)
            if (compareAndSetState(c, nextc))
                return nextc == 0;
        }
    }

实战资历

骨子里职业中,CountDownLatch适用于如下使用境况:
客商端的一个联合实行央浼查询顾客的高危害品级,服务端收到央浼后会央浼五个子系统获取数据,然后利用风险评估法规模型进行高风险评估。假若使用单线程去达成这么些操作,那些合伙伏乞超时的或者会相当的大,因为服务端供给多个子系统是各类排队的,央浼子系统获取数据的时光是线性累计的。那时候可以动用CountDownLatch,让多少个线程并发央浼三个子系统,当得到到多个子系统数据现在,再进行风险评估,那样央浼子系统获取数据的小时就相当于最耗费时间的可怜需要的小时,能够大大裁减管理时间。

await()

CountDownLatch提供await(卡塔尔(قطر‎方法来使当前线程在锁存器倒计数至零事前一向等候,除非线程被搁浅,定义如下:

    public void await() throws InterruptedException {
        sync.acquireSharedInterruptibly(1);
    }

await其里面采用AQS的acquireSharedInterruptibly(int arg卡塔尔国:

    public final void acquireSharedInterruptibly(int arg)
            throws InterruptedException {
        if (Thread.interrupted())
            throw new InterruptedException();
        if (tryAcquireShared(arg) < 0)
            doAcquireSharedInterruptibly(arg);
    }

在里面类Sync中重写了tryAcquireShared(int arg卡塔尔(英语:State of Qatar)方法:

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

getState(卡塔尔(قطر‎获取同步状态,其值等于流速計的值,从那边大家能够看来假使流速計值不等于0,则会调用doAcquireSharedInterruptibly(int arg卡塔尔,该方式为多个自旋方法会尝试一贯去获得同步状态:

    private void doAcquireSharedInterruptibly(int arg)
            throws InterruptedException {
        final Node node = addWaiter(Node.SHARED);
        boolean failed = true;
        try {
            for (;;) {
                final Node p = node.predecessor();
                if (p == head) {
                    /**
                     * 对于CountDownLatch而言,如果计数器值不等于0,那么r 会一直小于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);
        }
    }

要点解释

CountDownLatch允许贰个仍然多少个线程一贯等候,直到生龙活虎组其余操作施行到位。在选择CountDownLatch时,需求钦赐贰个整数值,此值是线程将在等待的操作数。当有个别线程为了要执行这个操作而等待时,须求调用await方法。await方法让线程步向休眠状态直到全数等待的操作完结甘休。当等待的有个别操作实行到位,它接受countDown方法来压缩CountDownLatch类的里边计数器。当在那之中计数器依次减少为0时,CountDownLatch会唤醒全数调用await方法而休眠的线程们。

福衢寿车分析

CountDownLatch布局如下

![](file:///G:/weizhi/myKnowledge/temp/9c1d9b85-25a1-4d47-9504-0801ed772abd/128/index_files/201702110002.jpg)

通过上边包车型客车构造图大家得以观望,CountDownLatch内部信任Sync达成,而Sync世袭AQS。CountDownLatch仅提供了四个构造方法:

CountDownLatch(int count卡塔尔(قطر‎ : 布局一个用给定计数开头化的 CountDownLatch

    public CountDownLatch(int count) {
        if (count < 0) throw new IllegalArgumentException("count < 0");
        this.sync = new Sync(count);
    }

sync为CountDownLatch的叁个中间类,其定义如下:

    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) {
            return (getState() == 0) ? 1 : -1;
        }

        //释放同步状态
        protected boolean tryReleaseShared(int releases) {
            for (;;) {
                int c = getState();
                if (c == 0)
                    return false;
                int nextc = c-1;
                if (compareAndSetState(c, nextc))
                    return nextc == 0;
            }
        }
    }

由此那几个里面类Sync我们能够清楚地看出CountDownLatch是行使共享锁来落到实处的。

源码深入深入分析

踏向源码深入分析早先先看一下CountDownLatch的类图,
澳门官网网址 2

Sync是CountDownLatch的四当中间类,它一连了AbstractQueuedSynchronizer。

CountDownLatch(int count卡塔尔、await(卡塔尔和countDown(卡塔尔三个办法是CountDownLatch的主干措施,本篇将深切剖析那八个点子的求实落实原理。

1.CountDownLatch(int count)

    public CountDownLatch(int count) {
        if (count < 0) throw new IllegalArgumentException("count < 0");
        this.sync = new Sync(count);
    }

该构造方法依照给定count参数布局三个CountDownLatch,内部创设了一个Sync实例。Sync是CountDownLatch的叁此中间类,其构造方法代码如下:

    Sync(int count) {
        setState(count);
    }

setState方法世袭自AQS,给Sync实例的state属性赋值。

    protected final void setState(int newState) {
        state = newState;
    }

以此state正是CountDownLatch的里边流量计。

2.await()
澳门官网网址,当await(卡塔尔国方法被调用时,当前线程会阻塞,直到内部计数器的值等于零或当前线程被暂停,下边深刻代码分析。

    public void await() throws InterruptedException {
        sync.acquireSharedInterruptibly(1);
    }

    public final void acquireSharedInterruptibly(int arg)
            throws InterruptedException {
        //如果当前线程中断,则抛出InterruptedException
        if (Thread.interrupted())
            throw new InterruptedException();
        //尝试获取共享锁,如果可以获取到锁直接返回;
        //如果获取不到锁,执行doAcquireSharedInterruptibly
        if (tryAcquireShared(arg) < 0)
            doAcquireSharedInterruptibly(arg);
    }

    //如果当前内部计数器等于零返回1,否则返回-1;
    //内部计数器等于零表示可以获取共享锁,否则不可以;
    protected int tryAcquireShared(int acquires) {
        return (getState() == 0) ? 1 : -1;
    }

    //返回内部计数器当前值
    protected final int getState() {
        return state;
    }

    //该方法使当前线程一直等待,直到当前线程获取到共享锁或被中断才返回
    private void doAcquireSharedInterruptibly(int arg)
        throws InterruptedException {
        //根据当前线程创建一个共享模式的Node节点
        //并把这个节点添加到等待队列的尾部
        //AQS等待队列不熟悉的可以查看AQS深入解析的内容
        final Node node = addWaiter(Node.SHARED);
        boolean failed = true;
        try {
            for (;;) {
                //获取新建节点的前驱节点
                final Node p = node.predecessor();
                //如果前驱节点是头结点
                if (p == head) {
                    //尝试获取共享锁
                    int r = tryAcquireShared(arg);
                    //获取到共享锁
                    if (r >= 0) {
                        //将前驱节点从等待队列中释放
                        //同时使用LockSupport.unpark方法唤醒前驱节点的后继节点中的线程
                        setHeadAndPropagate(node, r);
                        p.next = null; // help GC
                        failed = false;
                        return;
                    }
                }

                //当前节点的前驱节点不是头结点,或不可以获取到锁
                //shouldParkAfterFailedAcquire方法检查当前节点在获取锁失败后是否要被阻塞
                //如果shouldParkAfterFailedAcquire方法执行结果是当前节点线程需要被阻塞,则执行parkAndCheckInterrupt方法阻塞当前线程
                if (shouldParkAfterFailedAcquire(p, node) &&
                    parkAndCheckInterrupt())
                    throw new InterruptedException();
            }
        } finally {
            if (failed)
                cancelAcquire(node);
        }
    }

    private Node addWaiter(Node mode) {
        //根据当前线程创建一个共享模式的Node节点
        Node node = new Node(Thread.currentThread(), mode);
        // Try the fast path of enq; backup to full enq on failure
        Node pred = tail;
        //如果尾节点不为空(等待队列不为空),则新节点的前驱节点指向这个尾节点
        //同时尾节点指向新节点
        if (pred != null) {
            node.prev = pred;
            if (compareAndSetTail(pred, node)) {
                pred.next = node;
                return node;
            }
        }

        //如果尾节点为空(等待队列是空的)
        //执行enq方法将节点插入到等待队列尾部
        enq(node);
        return node;
    }

    //这里如果不熟悉的可以查看AQS深入解析的内容
    Node(Thread thread, Node mode) { // Used by addWaiter
        this.nextWaiter = mode;
        this.thread = thread;
    }

    private Node enq(final Node node) {
        //使用循环插入尾节点,确保成功插入
        for (;;) {
            Node t = tail;
            //尾节点为空(等待队列是空的)
            //新建节点并设置为头结点
            if (t == null) { // Must initialize
                if (compareAndSetHead(new Node()))
                    tail = head;
            } else {
                //否则,将节点插入到等待队列尾部
                node.prev = t;
                if (compareAndSetTail(t, node)) {
                    t.next = node;
                    return t;
                }
            }
        }
    }

    //获取当前节点的前驱节点
    final Node predecessor() throws NullPointerException {
        Node p = prev;
        if (p == null)
            throw new NullPointerException();
        else
            return p;
    }

    //判断当前节点里的线程是否需要被阻塞
    private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) {
        //前驱节点线程的状态
        int ws = pred.waitStatus;
        //如果前驱节点线程的状态是SIGNAL,返回true,需要阻塞线程
        if (ws == Node.SIGNAL)
            return true;
        //如果前驱节点线程的状态是CANCELLED,则设置当前节点的前去节点为"原前驱节点的前驱节点"
        //因为当前节点的前驱节点线程已经被取消了
        if (ws > 0) {
            do {
                node.prev = pred = pred.prev;
            } while (pred.waitStatus > 0);
            pred.next = node;
        } else {
            //其它状态的都设置前驱节点为SIGNAL状态
            compareAndSetWaitStatus(pred, ws, Node.SIGNAL);
        }
        return false;
    }

    //通过使用LockSupport.park阻塞当前线程
    //同时返回当前线程是否中断
    private final boolean parkAndCheckInterrupt() {
        LockSupport.park(this);
        return Thread.interrupted();
    }

3.countDown()
里头流量计减生机勃勃,假使计数到达零,唤醒全体等待的线程。

    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) {
        for (;;) {
            //获取内部计数器状态值
            int c = getState();
            if (c == 0)
                return false;
            //计数器减一
            int nextc = c-1;
            //使用CAS修改state值
            if (compareAndSetState(c, nextc))
                return nextc == 0;
        }
    }

    private void doReleaseShared() {
        for (;;) {
            //从头结点开始
            Node h = head;
            //头结点不为空,并且不是尾节点
            if (h != null && h != tail) {
                int ws = h.waitStatus;
                if (ws == Node.SIGNAL) {
                    if (!compareAndSetWaitStatus(h, Node.SIGNAL, 0))
                        continue;
                    //唤醒阻塞的线程
                    unparkSuccessor(h);
                }
                else if (ws == 0 &&
                        !compareAndSetWaitStatus(h, 0, Node.PROPAGATE))
                    continue;
            }
            if (h == head)
                break;
        }
    }

    private void unparkSuccessor(Node node) {
        int ws = node.waitStatus;
        if (ws < 0)
            compareAndSetWaitStatus(node, ws, 0);
        Node s = node.next;
        if (s == null || s.waitStatus > 0) {
            s = null;
            for (Node t = tail; t != null && t != node; t = t.prev)
                if (t.waitStatus <= 0)
                    s = t;
        }

        if (s != null)
            //通过使用LockSupport.unpark唤醒线程
            LockSupport.unpark(s.thread);
    }

CountDownLatch

实例演示

上面代码演示了CountDownLatch轻易使用。演示的境况是5位选手参预跑步竞技,发令枪打响后,5个放大计时器伊始分级计时,直到全数选手都到达尖峰。

public class CountDownLatchDemo {
    public static void main(String[] args) {
        Timer timer = new Timer(5);
        new Thread(timer).start();
        for (int athleteNo = 0; athleteNo < 5; athleteNo++) {
            new Thread(new Athlete(timer, "athlete" + athleteNo)).start();
        }
    }
}

class Timer implements Runnable {
    CountDownLatch timerController;
    public Timer(int numOfAthlete) {
        this.timerController = new CountDownLatch(numOfAthlete);
    }

    public void recordResult(String athleteName) {
        System.out.println(athleteName + " has arrived");
        timerController.countDown();
        System.out.println("There are " + timerController.getCount() + " athletes did not reach the end");
    }

    @Override
    public void run() {
        try {
            System.out.println("Start...");
            timerController.await();
            System.out.println("All the athletes have arrived");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

class Athlete implements Runnable {
    Timer timer;
    String athleteName;

    public Athlete(Timer timer, String athleteName) {
        this.timer = timer;
        this.athleteName = athleteName;
    }

    @Override
    public void run() {
        try {
            System.out.println(athleteName + " start running");
            long duration = (long) (Math.random() * 10);
            Thread.sleep(duration * 1000);
            timer.recordResult(athleteName);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

输出结果如下所示:

Start...
athlete0 start running
athlete1 start running
athlete2 start running
athlete3 start running
athlete4 start running
athlete0 has arrived
There are 4 athletes did not reach the end
athlete3 has arrived
There are 3 athletes did not reach the end
athlete2 has arrived
athlete1 has arrived
There are 1 athletes did not reach the end
There are 2 athletes did not reach the end
athlete4 has arrived
There are 0 athletes did not reach the end
All the athletes have arrived

countDown()

CountDownLatch提供countDown(卡塔尔(قطر‎方法依次减少锁存器的计数,如若计数达到零,则释放具备等待的线程。

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

中间调用AQS的releaseShared(int arg卡塔尔(قطر‎方法来刑释分享锁同步状态:

    public final boolean releaseShared(int arg) {
        if (tryReleaseShared(arg)) {
            doReleaseShared();
            return true;
        }
        return false;
    }

tryReleaseShared(int arg卡塔尔(英语:State of Qatar)方法被CountDownLatch的中间类Sync重写:

    protected boolean tryReleaseShared(int releases) {
        for (;;) {
            //获取锁状态
            int c = getState();
            //c == 0 直接返回,释放锁成功
            if (c == 0)
                return false;
            //计算新“锁计数器”
            int nextc = c-1;
            //更新锁状态(计数器)
            if (compareAndSetState(c, nextc))
                return nextc == 0;
        }
    }

原理计算

使用CountDownLatch(int count卡塔尔创设CountDownLatch实例,将count参数赋值给内部流速計state,调用await(卡塔尔(قطر‎方法梗塞当前线程,并将如今线程封装参加到等候队列中,直到state等于零或当前线程被暂停;调用countDown(卡塔尔国方法使state值减意气风发,假若state等于零则唤醒等待队列中的线程。

await()

CountDownLatch提供await(卡塔尔国方法来使当前线程在锁存器倒计数至零事情未发生前一贯等候,除非线程被搁浅,定义如下:

    public void await() throws InterruptedException {
        sync.acquireSharedInterruptibly(1);
    }

await其里面使用AQS的acquireSharedInterruptibly(int arg卡塔尔:

    public final void acquireSharedInterruptibly(int arg)
            throws InterruptedException {
        if (Thread.interrupted())
            throw new InterruptedException();
        if (tryAcquireShared(arg) < 0)
            doAcquireSharedInterruptibly(arg);
    }

在中间类Sync中重写了tryAcquireShared(int arg卡塔尔(قطر‎方法:

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

getState(卡塔尔(英语:State of Qatar)获取同步状态,其值等于计数器的值,今后间大家得以观望如果流量计值不等于0,则会调用doAcquireSharedInterruptibly(int arg卡塔尔(قطر‎,该方法为三个自旋方法会尝试一向去获得同步状态:

    private void doAcquireSharedInterruptibly(int arg)
            throws InterruptedException {
        final Node node = addWaiter(Node.SHARED);
        boolean failed = true;
        try {
            for (;;) {
                final Node p = node.predecessor();
                if (p == head) {
                    /**
                     * 对于CountDownLatch而言,如果计数器值不等于0,那么r 会一直小于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);
        }
    }

采取示范

示范还是使用开会案例。总首席营业官走入会议厅等待5个人全体达到开会地点才会开会。所以那边有三个线程首席营业官等待开会线程、职员和工人到达开会地点:

public class CountDownLatchTest {
    private static CountDownLatch countDownLatch = new CountDownLatch(5);

    /**
     * Boss线程,等待员工到达开会
     */
    static class BossThread extends Thread{
        @Override
        public void run() {
            System.out.println("Boss在会议室等待,总共有" + countDownLatch.getCount() + "个人开会...");
            try {
                //Boss等待
                countDownLatch.await();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            System.out.println("所有人都已经到齐了,开会吧...");
        }
    }

    //员工到达会议室
    static class EmpleoyeeThread  extends Thread{
        @Override
        public void run() {
            System.out.println(Thread.currentThread().getName() + ",到达会议室....");
            //员工到达会议室 count - 1
            countDownLatch.countDown();
        }
    }

    public static void main(String[] args){
        //Boss线程启动
        new BossThread().start();

        for(int i = 0 ; i < countDownLatch.getCount() ; i++){
            new EmpleoyeeThread().start();
        }
    }
}

运作结果:

此篇博客全数源码均出自JDK 1.8

在上篇博客中介绍了Java四大现身工具之朝气蓬勃的CyclicBarrier,明日要介绍的CountDownLatch与CyclicBarrier有点儿相似。
CyclicBarrier所描述的是“允许生龙活虎组线程互相等待,直到达到有些公共屏障点,才会开展一而再再而三职责",而CountDownLatch所描述的是”在成功风流倜傥组正在别的线程中实施的操作此前,它同意二个或多少个线程一向守候“。在API中是如此陈述的:

用给定的计数 起先化 CountDownLatch。由于调用了 countDown()方法,所以在这里时此刻计数达到零在此之前,await 方法会一向受梗塞。之后,会放出具备等待的线程,await 的具有继续调用都将及时重临。这种景观只现出三遍——计数无法被重新复苏设置。假设要求重新设置计数,请思考动用 Cyclic巴里r。

![](file:///G:/weizhi/myKnowledge/temp/9c1d9b85-25a1-4d47-9504-0801ed772abd/128/index_files/2017021200001.png)

CountDownLatch是经过一个计数器来促成的,当大家在new 五个CountDownLatch对象的时候须要带入该流速計值,该值就意味着了线程的多少。每当叁个线程达成本身的任务后,流速計的值就能减1。当流速计的值变为0时,就代表具有的线程均已经成功了义务,然后就足以过来等待的线程继续施行了。

尽管如此,CountDownlatch与CyclicBarrier有那么点平日,但是他们大概存在部分有别于的:

  1. CountDownLatch的成效是允许1或N个线程等待其余线程实现实践;而Cyclic巴里r则是允许N个线程互相等待
  2. CountDownLatch的计数器不大概被重新复苏设置;Cyclic巴里r的流速計能够被重置后使用,因而它被可以称作是循环的barrier

此篇博客全部源码均源于JDK 1.8

await()

CountDownLatch提供await(卡塔尔(英语:State of Qatar)方法来使当前线程在锁存器倒计数至零事情未发生前一向等候,除非线程被搁浅,定义如下:

    public void await() throws InterruptedException {
        sync.acquireSharedInterruptibly(1);
    }

await其内部接纳AQS的acquireSharedInterruptibly(int arg卡塔尔:

    public final void acquireSharedInterruptibly(int arg)
            throws InterruptedException {
        if (Thread.interrupted())
            throw new InterruptedException();
        if (tryAcquireShared(arg) < 0)
            doAcquireSharedInterruptibly(arg);
    }

在中间类Sync中重写了tryAcquireShared(int arg卡塔尔(英语:State of Qatar)方法:

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

getState(卡塔尔(英语:State of Qatar)获取同步状态,其值等于流速计的值,从那边大家能够观看假若流量计值不等于0,则会调用doAcquireSharedInterruptibly(int arg卡塔尔国,该形式为八个自旋方法会尝试一向去获得同步状态:

    private void doAcquireSharedInterruptibly(int arg)
            throws InterruptedException {
        final Node node = addWaiter(Node.SHARED);
        boolean failed = true;
        try {
            for (;;) {
                final Node p = node.predecessor();
                if (p == head) {
                    /**
                     * 对于CountDownLatch而言,如果计数器值不等于0,那么r 会一直小于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);
        }
    }

福衢寿车深入分析

CountDownLatch构造如下

澳门官网网址 3

CountDownLatch

因而地点的布局图我们能够见到,CountDownLatch内部注重Sync完结,而Sync世袭AQS。CountDownLatch仅提供了三个布局方法:

CountDownLatch(int count卡塔尔国 : 构造一个用给定计数起头化的 CountDownLatch

    public CountDownLatch(int count) {
        if (count < 0) throw new IllegalArgumentException("count < 0");
        this.sync = new Sync(count);
    }

sync为CountDownLatch的二个里头类,其定义如下:

    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) {
            return (getState() == 0) ? 1 : -1;
        }

        //释放同步状态
        protected boolean tryReleaseShared(int releases) {
            for (;;) {
                int c = getState();
                if (c == 0)
                    return false;
                int nextc = c-1;
                if (compareAndSetState(c, nextc))
                    return nextc == 0;
            }
        }
    }

透过这几个里面类Sync大家得以通晓地来看CountDownLatch是应用分享锁来兑现的。

CountDownLatch内部通过分享锁完毕。在创造CountDownLatch实例时,需求传递贰个int型的参数:count,该参数为流量计的起来值,也足以知道为该分享锁能够获得的总次数。当某些线程调用await(卡塔尔(英语:State of Qatar)方法,程序首先判定count的值是或不是为0,假设不会0的话则会一贯等待直到为0结束。当别的线程调用countDown(卡塔尔国方法时,则推行释放分享锁状态,使count值

1。当在创造CountDownLatch时起始化的count参数,必定要有count线程调用countDown方法才会使流速計count等于0,锁才会放出,前边等待的线程才会接二连三运转。注意CountDownLatch不能够回滚重新设置。

有关分享锁的请仿效:【死磕Java并发】-----J.U.C之AQS:同步状态的收获与释放

总结

本文由澳门网络娱乐游戏平台发布于编程,转载请注明出处:高并发编制程序-CountDownLatch深刻剖判

相关阅读