DengQN·一个普通程序员;
CountDownLatch
2019-02-07 14:50 60
#线程#之前#等待#一直#会#方法#执行#最后

在我开门之前谁也别想动

CountDownLatch 是Java Concurrent 包里边的一个同步工具类。它可以使一个或多个线程等待一个事件发生。

CountDownLatch 有一个计数器,表示等待的事件数量。以及一个await方法,当计数器一直大于零的时候,会一直等待。

一般有两种用法,创建一组线程,让他们并发的执行 或者 等待,直到所有的线程完成任务。当然用来做一些有先后顺序的工作也很好用。

await方法

一直追踪这个方法,在AbstractQueuedSynchronizer有这段代码

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

在CountDownLatch里有个内部类Sync,实现了AbstractQueuedSynchronizer,在初始化CountDownLatch的时候,初始化Sync,同时生成一个

队列(链表),根据CountDownLatch(size)的size,来生成Node,在最后一个就剩head之前会一直循环(Await)。

也就是说,调用await的时候,尝试获取共享锁,然后失败,因为节点不是head,所以会加入到tail(CAS方式添加)。

1
CountDownLatch startLatch = new CountDownLatch(1);
        for (int i = 0; i < 10; i++) {
            new Thread(() -> {
                try {
                    startLatch.await();
                    System.out.println(Instant.now());
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }).start();
        }
System.out.println("start...");
startLatch.countDown();

所有线程因为count是1,被卡住,直到countdown。

2
CountDownLatch waitLatch = new CountDownLatch(10);
for (int i = 0; i < 10; i++) {
    int finalI = i;
    new Thread(() -> {
        try {
            Thread.sleep(new Random().nextInt(2000));
            System.out.println("i: " + finalI);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            waitLatch.countDown();
        }
    }).start();
}
waitLatch.await();
System.out.println("end");

最后输出end被执行之前要先执行完之前的线程,因为count>0,如果count的初始值过小,就会提前输出最后的end

i: 8
i: 3
i: 6
i: 5
i: 0
end
i: 4
i: 1
i: 9
i: 7
i: 2