展开
拓展 关闭
订阅号推广码
GitHub
视频
公告栏 关闭

CountDownLatch使用及源码分析

  • 简介
await()  进入等待的状态
countDown()  计数器减一
  • 代码案例
import java.util.concurrent.CountDownLatch;

public class CountDownLatchDemo {

    public static void main(String[] args) {
        CountDownLatch countDownLatch = new CountDownLatch(8);
        new Thread(()->{
            try {
                countDownLatch.await();     // 当前线程进入等待状态,需等下面8个线程执行完毕后才执行
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("800米比赛结束,准备清空跑道并继续跨栏比赛");
        }).start();

        for (int i = 0; i < 8; i++) {
            int finalI = i;
            new Thread(()->{
                try {
                    Thread.sleep(finalI * 1000L);
                    System.out.println(Thread.currentThread().getName()+"到达终点");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } finally {
                    countDownLatch.countDown();         // 当某个线程执行完毕后,计数器减1
                }
            }).start();
        }
    }

}

# 控制台执行结果:
Thread-1到达终点
Thread-2到达终点
Thread-3到达终点
Thread-4到达终点
Thread-5到达终点
Thread-6到达终点
Thread-7到达终点
Thread-8到达终点
800米比赛结束,准备清空跑道并继续跨栏比赛
  • 源码分析
# ctrl 查看await方法
    public void await() throws InterruptedException {
        sync.acquireSharedInterruptibly(1);
    }

# sync继承了aqs
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;
            }
        }
    }

# 当我们new CountDownLatch对象时,实际上是new sync
    public CountDownLatch(int count) {
        if (count < 0) throw new IllegalArgumentException("count < 0");
        this.sync = new Sync(count);
    }

# 查看sync
Sync(int count) {
    setState(count);      // 赋值 state,即是count
}

# 返回await方法
    public void await() throws InterruptedException {
        sync.acquireSharedInterruptibly(1);
    }

# 继续查看acquireSharedInterruptibly方法
    public final void acquireSharedInterruptibly(int arg)
            throws InterruptedException {
        if (Thread.interrupted())            // 判断线程是否是中断状态
            throw new InterruptedException();
        if (tryAcquireShared(arg) < 0)      // 否则执行tryAcquireShared方法
            doAcquireSharedInterruptibly(arg);
    }

# 查看实现类
    protected int tryAcquireShared(int arg) {
        throw new UnsupportedOperationException();
    }

        protected int tryAcquireShared(int acquires) {
            return (getState() == 0) ? 1 : -1;      // 判断状态是否为0,为0则返回1,否则返回-1
        }

# 再次返回acquireSharedInterruptibly方法
    public final void acquireSharedInterruptibly(int arg)
            throws InterruptedException {
        if (Thread.interrupted())
            throw new InterruptedException();
        if (tryAcquireShared(arg) < 0)            // 当返回值小于0时,执行doAcquireSharedInterruptibly方法
            doAcquireSharedInterruptibly(arg);
    }

# 查看doAcquireSharedInterruptibly方法
    private void doAcquireSharedInterruptibly(int arg)
        throws InterruptedException {
        final Node node = addWaiter(Node.SHARED);      // 添加1个节点
        try {
            for (;;) {
                final Node p = node.predecessor();
                if (p == head) {        // 判断node.predecessor是否等于head
                    int r = tryAcquireShared(arg);        // 判断状态是否等于0
                    if (r >= 0) {
                        setHeadAndPropagate(node, r);
                        p.next = null; // help GC
                        return;
                    }
                }
                if (shouldParkAfterFailedAcquire(p, node) &&      // 否则挂起
                    parkAndCheckInterrupt())
                    throw new InterruptedException();
            }
        } catch (Throwable t) {
            cancelAcquire(node);
            throw t;
        }
    }
  • 查看countDown方法
    public void countDown() {
        sync.releaseShared(1);
    }

# 查看releaseShared方法
    public final boolean releaseShared(int arg) {
        if (tryReleaseShared(arg)) {
            doReleaseShared();
            return true;
        }
        return false;
    }

# 查看实现类
    protected boolean tryReleaseShared(int arg) {
        throw new UnsupportedOperationException();
    }

        protected boolean tryReleaseShared(int releases) {
            // Decrement count; signal when transition to zero
            for (;;) {        // 执行死循环
                int c = getState();      // 获取状态
                if (c == 0)
                    return false;        // 等于0 则返回false
                int nextc = c - 1;        // 否则继续执行操作
                if (compareAndSetState(c, nextc))
                    return nextc == 0;      // 最后返回0
            }
        }

# 返回releaseShared方法
    public final boolean releaseShared(int arg) {
        if (tryReleaseShared(arg)) {
            doReleaseShared();      // 当8个线程的计数器减少为0时,执行doReleaseShared方法
            return true;
        }
        return false;
    }

# 查看doReleaseShared方法
    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 (!h.compareAndSetWaitStatus(Node.SIGNAL, 0))
                        continue;            // loop to recheck cases
                    unparkSuccessor(h);
                }
                else if (ws == 0 &&
                         !h.compareAndSetWaitStatus(0, Node.PROPAGATE))
                    continue;                // loop on failed CAS
            }
            if (h == head)                   // loop if head changed
                break;
        }
    }
posted @ 2022-05-16 10:40  DogLeftover  阅读(16)  评论(0编辑  收藏  举报