CountDownLatch 源码分析

1. 类介绍

一个同步辅助类,在完成一组正在其余线程中执行的操做以前,它容许一个或多个线程一直等待。用给定的计数 初始化 CountDownLatch。因为调用了 countDown() 方法,因此在当前计数到达零以前,await 方法会一直受阻塞。以后,会释放全部等待的线程,await 的全部后续调用都将当即返回。这种现象只出现一次——计数没法被重置。源码分析

2. 使用场景

在一些应用场合中,须要等待某个条件达到要求后才能作后面的事情。
CountDownLatch最重要的方法是countDown()和await()两个方法,countDown主要是倒数一次,await是等待倒数到0,若是没有到达0,就只有阻塞等待了。
例如:
A 和 B 相约一块儿吃饭,等A和B都到指定顶点后才能开始吃饭,下面用代码模拟实现。ui

示例

public class CountDownLatchTest {
    static CountDownLatch c = new CountDownLatch(2);
    
    public static void main(String[] args) {
        new Thread(new Runnable() {
            public void run() {
                System.out.println("A 我来了");
                c.countDown();
            }
        }).start();

        new Thread(new Runnable() {
            public void run() {
                System.out.println("B 我来了");
                c.countDown();
            }
        }).start();

        new Thread(new Runnable() {
            public void run() {
                try {
                    c.await();
                    System.out.println("开始吃饭...");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }).start();

    }
}

源码分析:

须要提早了解:AbstractQueuedSynchronizer 源码分析this

AQS提供了两种模式:独占模式&共享模式。CountDownLatch就是一个使用共享模式的自定义同步器实现的共享锁。spa

CountDownLatch 代码很少,主要是经过内部类继承AQS来实现其功能的,下面咱们一步一步来分析下源码:.net

Sync 内部类

private static final class Sync extends AbstractQueuedSynchronizer {
    private static final long serialVersionUID = 4982264981922014374L;

    //构造Sync对象是初始化AQS中state的数量(共享锁的个数)
    Sync(int count) {
        setState(count);
    }

    //获取当前state的数量(共享锁个数)
    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;
        }
    }
}

AbstractQueuedSynchronizer 类采用模版模式进行扩展实现其相应的功能。子类只须要实现
以下5个方法就能实现其不一样功能的锁。线程

而CountDownLatch 的内部类Sync使用的是共享锁因此只实现了tryAcquireShared和tryReleaseShared方法。code

CountDownLatch的构造方法

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

建立CountDownLatch对象时,须要传入一个int的计数器。对象

await 方法

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

public boolean await(long timeout, TimeUnit unit)
    throws InterruptedException {
    return sync.tryAcquireSharedNanos(1, unit.toNanos(timeout));
}

await方法调用AQS的得到锁的方法,只有AQS的state状态为0时才能得到锁,若是state不为0,则须要在AQS的等待队列中阻塞等待。blog

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

countDown方法则调用AQS的releaseShared方法,释放共享锁,也就是每次将state状态每次减一,直到减到0,则唤醒队列中的全部节点(线程)。继承

public long getCount() {
    return sync.getCount();
}

获取计数器当前值。

相关文章
相关标签/搜索