欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

JUC下工具类CountDownLatch用法以及源码理解

程序员文章站 2022-06-10 14:42:35
CountDownLoatch是JUC下一个用于控制计数的计数器,比如我需要从6开始计数,每个线成运行完之后计数减一,等计数器到0时候开始执行其他任务。 public static void main(String[] args) throws InterruptedException { Coun ......

countdownloatch是juc下一个用于控制计数的计数器,比如我需要从6开始计数,每个线成运行完之后计数减一,等计数器到0时候开始执行其他任务。

public static void main(string[] args) throws interruptedexception {
        countdownlatch countdownlatch = new countdownlatch(6);
        for (int i = 0; i < 6; i++) {
            new thread(() -> {
                system.out.println(thread.currentthread().getname() + "\t结束");
                countdownlatch.countdown();
            }, string.valueof(i)).start();
        }
        countdownlatch.await();
        system.out.println("开始执行新任务");
    }

现在让我们来看下countdownloach的底层源码

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) {
            // 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;
            }
        }
    }

    private final sync sync;

这里最重要的是这个tyrreleaseshared方法,countdownlatch也是实现了aqs机制,通过state去判断资源知否被占用。当我们使用countdow函数去减1时,会触发releaseshared方法,这个方法的参数时每次减的次数,默认是1

public void countdown() {
        sync.releaseshared(1);
}

我们点进去看看这个方法是如何实现的

 public final boolean releaseshared(int arg) {
        if (tryreleaseshared(arg)) {
            doreleaseshared();
            return true;
        }
        return false;
    }

这个方法调用了aqs的releaseshared,他会先去尝试减一,判断是否减一成功

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;
            }
        }

这里使用了cas自旋机制对state(我们这里是6)进行减1,如果自旋成功就会返回true即6一个一个减最后变成0,就会执行下面的doreleaseshared方法

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;            // loop to recheck cases
                    unparksuccessor(h);
                }
                else if (ws == 0 &&
                         !compareandsetwaitstatus(h, 0, node.propagate))
                    continue;                // loop on failed cas
            }
            if (h == head)                   // loop if head changed
                break;
        }
    }

这里使用了locksupport相关的加锁解锁,unpark有关这个我会在之后有空的时候进行解析,通过对aqs任务队列进行判断,是否只有头节点和尾节点,这个任务队列里面头节点并不是真正的任务,而是为了初始化方便操作的哨兵节点,然后对第一个任务节点进行操作,就是我们这6步操作,每次减一作为一个任务进行释放(我自己认为的)。

 

这是我第一次发帖子希望大家多多支持,准备秋招了,争取大厂上岸,如果帖子里有错误希望大家积极提出来