• CountDownLatch源码分析


    CountDownLatch的两个核心用法

    1.一个线程等待多个线程执行完之后再去执行

    2.多个线程等待一个线程执行完之后再去执行

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

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

    每次都用Countdown,state的值就减一,只有当减到0时,才会返回true,唤醒线程.

    private void doReleaseShared() {
            /*
             * Ensure that a release propagates, even if there are other
             * in-progress acquires/releases.  This proceeds in the usual
             * way of trying to unparkSuccessor of head if it needs
             * signal. But if it does not, status is set to PROPAGATE to
             * ensure that upon release, propagation continues.
             * Additionally, we must loop in case a new node is added
             * while we are doing this. Also, unlike other uses of
             * unparkSuccessor, we need to know if CAS to reset status
             * fails, if so rechecking.
             */
            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;
            }
        }

    await方法

     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)
                doAcquireSharedInterruptibly(arg);
        }
     protected int tryAcquireShared(int acquires) {
                return (getState() == 0) ? 1 : -1;
            }
    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) {
                        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);
            }
        }

    await方法非常清晰,只有当state为0时才返回true,其他一律返回false

  • 相关阅读:
    minikube国内在线部署体验
    分表与分库使用场景以及设计方式
    epool与select有什么区别
    使用ssh-keygen生成私钥和公钥
    mysql关键字冲突
    MySQL 获取当前时间戳
    平时常说的ThreadLocal,今天就彻底解决它
    mysql和mssql最大连接数
    Spring Boot实战:拦截器与过滤器
    Mysql 索引问题-日期索引使用
  • 原文地址:https://www.cnblogs.com/lzh66/p/13234315.html
Copyright © 2020-2023  润新知