美文网首页
Android 等待多个线程完成的CountDownLatch

Android 等待多个线程完成的CountDownLatch

作者: Bfmall | 来源:发表于2021-04-21 22:33 被阅读0次

CountDownLatch介绍

CountDownLatch是一个同步工具类,它允许一个或多个线程一直等待,直到其他线程执行完后再执行。例如,应用程序的主线程希望在负责启动框架服务的线程已经启动所有框架服务之后执行。

CountDownLatch原理

CountDownLatch是通过一个计数器来实现的,计数器的初始化值为线程的数量。每当一个线程完成了自己的任务后,计数器的值就相应得减1。当计数器到达0时,表示所有的线程都已完成任务,然后在闭锁上等待的线程就可以恢复执行任务。

image

CountDownLatch的伪代码

Main thread start
Create CountDownLatch for N threads
Create and start N threads
Main thead wait on latch
N threads completes there tasks are returns
Main thread resume execution

CountDownLatch.java中定义的构造函数

//用等待的线程数量来进行初始化
public void CountDownLatch(int count){...}

计数器count是闭锁需要等待的线程数量,只能被设置一次,且CountDownLatch没有提供任何机制去重新设置计数器count。

与CountDownLatch的第一次交互是主线程等待其他线程。主线程必须在启动其他线程后立即调用CountDownLatch.await()方法。这样主线程的操作就会在这个方法上阻塞,直到其他线程完成各自的任务。

其他N个线程必须引用CountDownLatch闭锁对象,因为它们需要通知CountDownLatch对象,它们各自完成了任务;这种通知机制是通过CountDownLatch.countDown()方法来完成的;每调用一次,count的值就减1,因此当N个线程都调用这个方法,count的值就等于0,然后主线程就可以通过await()方法,恢复执行自己的任务。

在实时系统中的使用场景

  1. 实现最大的并行性:有时我们想同时启动多个线程,实现最大程度的并行性。例如,我们想测试一个单例类。如果我们创建一个初始计数器为1的CountDownLatch,并让其他所有线程都在这个锁上等待,只需要调用一次countDown()方法就可以让其他所有等待的线程同时恢复执行。
  2. 开始执行前等待N个线程完成各自任务:例如应用程序启动类要确保在处理用户请求前,所有N个外部系统都已经启动和运行了。
  3. 死锁检测:一个非常方便的使用场景是你用N个线程去访问共享资源,在每个测试阶段线程数量不同,并尝试产生死锁。

测试
先上实例代码,创建了5个线程,2个等待线程,3个执行 countdown 线程。

import java.util.concurrent.CountDownLatch;

import android.app.Activity;
import android.os.Bundle;
import android.util.Log;

public class Test2Activity extends Activity {
    private CountDownLatch mCountDownLatch;
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.test_layout);
        
        mCountDownLatch = new CountDownLatch(3);
        
        new Thread(new Runnable() {
            
            @Override
            public void run() {
                try {
                    Log.d("TAG", "Thread Main A start:"+mCountDownLatch.getCount());
                    mCountDownLatch.await();
                    Log.d("TAG", "Thread Main A end:"+mCountDownLatch.getCount());
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }).start();
        
        new Thread(new Runnable() {
            
            @Override
            public void run() {
                try {
                    Log.d("TAG", "Thread Main B start:"+mCountDownLatch.getCount());
                    mCountDownLatch.await();
                    Log.d("TAG", "Thread Main B end:"+mCountDownLatch.getCount());
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }).start();
        
        new Thread(new Runnable() {
            
            @Override
            public void run() {
                mCountDownLatch.countDown();
                Log.d("TAG", "Thread A:"+mCountDownLatch.getCount());
            }
        }).start();
        
        new Thread(new Runnable() {
            
            @Override
            public void run() {
                mCountDownLatch.countDown();
                Log.d("TAG", "Thread B:"+mCountDownLatch.getCount());
            }
        }).start();
        
        new Thread(new Runnable() {
            
            @Override
            public void run() {
                mCountDownLatch.countDown();
                Log.d("TAG", "Thread C:"+mCountDownLatch.getCount());
            }
        }).start();
        
    }

执行结果:

image.png

从打印的结果,我们可以看到,2 个等待线程都是在其他三个线程执行完 countDown() 再执行下一步的任务。CountDownLatch 使用起来也是挺简单的,没有过多的,复杂的方法。就像发射火箭,开始倒计时,然后发射,收工,不用考虑重复使用同一火箭。一次性使用,无后顾之忧!!!

相关文章

网友评论

      本文标题:Android 等待多个线程完成的CountDownLatch

      本文链接:https://www.haomeiwen.com/subject/vrpolltx.html