CountDownLatch

本文源码基于Android Sdk 26,打开Android Studio,把CompileSdk改为26,即可找到Android Sdk 26对应的CountDownLatch的源码。

定义

我们看下源码的解释:A synchronization aid that allows one or more threads to wait until a set of operations being performed in other threads completes.
翻译一下:CountDownLatch是一个同步辅助类,它可以让一个或多个线程等待,直到其他线程执行完一系列操作。

常用方法

countdown():CountDownLatch在初始化时,需要给定一个整数作为计数器。当调用countDown()时,计数器会减1。
await():如果计数器大于0,调用await()的线程会阻塞,一直到计数器被countDown()减到0,线程才会继续执行。计数器是无法重置的,当计数器被减到0时,调用await()会直接返回。

举例

源码中已经给了一个示例:有一个Boss和几名打工人,Boss说“你们可以开始干活了”,打工人才可以开始干活。等到所有的打工人活干完了,Boss开始给打工人发盒饭。这里需要2个CountDownLatch,一个是Boss通知打工人可以开始干活了,打工人才开始干活;一个是Boss等待所有打工人活干完了,才开始发盒饭。代码如下:

public class Worker implements Runnable {
    private final CountDownLatch startSignal;
    private final CountDownLatch doneSignal;
    Worker(CountDownLatch startSignal, CountDownLatch doneSignal) {
        this.startSignal = startSignal;
        this.doneSignal = doneSignal;
    }

    public void run() {
        try {
            startSignal.await();
            doWork();
            doneSignal.countDown();
        } catch (InterruptedException ex) {
        }
    } // return;

    void doWork() {
        System.out.println(Thread.currentThread().getName() + " start to do work!");
    }
}
public class Driver { // ...

    private static final int N = 6;//the number of workers

    public static void main(String[] args) throws InterruptedException {
        CountDownLatch startSignal = new CountDownLatch(1);
        CountDownLatch doneSignal = new CountDownLatch(N);
        for (int i = 0; i < N; ++i) // create and start threads
            new Thread(new Worker(startSignal, doneSignal)).start();
        bossSaidStartWorking();       // don't let run yet
        startSignal.countDown();      // let all threads proceed
        doneSignal.await();           // wait for all to finish
        bossSaidTimeForDinner();
    }

    private static void bossSaidStartWorking(){
        System.out.println("Now you can start working!");
    }

    private static void bossSaidTimeForDinner(){
        System.out.println("Now you can start eating!");
    }
}

运行后的打印如下:

Now you can start working!
Thread-2 start to do work!
Thread-7 start to do work!
Thread-3 start to do work!
Thread-6 start to do work!
Thread-4 start to do work!
Thread-5 start to do work!
Now you can start eating!

如果有个打工人活一直没干完,Boss不可能让所有人一直等他,饭都凉了。于是Boss通知大家:我最多等30分钟,我们就开始吃饭。我们把doneSignal.await();改成doneSignal.await(30, TimeUnit.MINUTES);即可实现该需求。

实现原理

CountDownLatch类中的await()和countDown()实际操作的对象是内部类Sync,而Sync继承自 AbstractQueuedSynchronizer类,其中维护了一个整数state,使用volatile进行了修饰:

private volatile int state;

在 countDown()中调用了Sync实例的releaseShared(1):

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

其中的releaseShared(1),先对计数器进行减1操作,如果减1后的计数器为0,唤醒被await()阻塞的所有线程,具体是这样的:

public final boolean releaseShared(int arg) {
    if (tryReleaseShared(arg)) { //对计数器进行减1操作
        doReleaseShared();//如果计数器为0,唤醒被await()阻塞的所有线程
        return true;
    }
    return false;
}

其中的tryReleaseShared()的具体实现在Sync类中,它先获取当前计数器的值,如果计数器为0时,就直接返回;如果不为0,使用CAS方法对计数器进行减1操作:

protected boolean tryReleaseShared(int releases) {
    for (;;) {//死循环,如果CAS操作失败就会不断继续尝试。
        int c = getState();//获取当前计数器的值。
        if (c == 0)// 计数器为0时,就直接返回。
            return false;
        int nextc = c-1;
        if (compareAndSetState(c, nextc))// 使用CAS方法对计数器进行减1操作
            return nextc == 0;//如果操作成功,返回计数器是否为0
    }
}

在await()中,只调用了Sync实例的acquireSharedInterruptibly(1):

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

其中acquireSharedInterruptibly(1),判断计数器是否为0,如果不为0则阻塞当前线程:

public final void acquireSharedInterruptibly(int arg) throws InterruptedException {
    if (Thread.interrupted())
        throw new InterruptedException();
    if (tryAcquireShared(arg) < 0)//判断计数器是否为0
        doAcquireSharedInterruptibly(arg);//如果不为0则阻塞当前线程
}

其中tryAcquireShared()是AbstractQueuedSynchronizer中的一个模板方法,其具体实现在Sync类中,其主要是判断计数器是否为零,如果为零则返回1,如果不为零则返回-1:

protected int tryAcquireShared(int acquires) {
    return (getState() == 0) ? 1 : -1;
}

参考:https://blog.csdn.net/heihaozi/article/details/105738230

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值