工具类:并发任务管理器ConcurrentTasksManager

在app开发中经常会有这样一种需求:在多个线程中并发执行多个任务,当且仅当这些任务全部完成时,才继续进行下一步操作。以app的欢迎页为例,通常需要同时做这样几件事:1 获取基础的配置信息 2 检查更新 3 计时n秒(这是为了保证欢迎页至少被展示n秒),当且仅当这3个任务均被完成时,才跳转到app的主界面。

通常的做法是写几个状态变量与并发执行的任务一一对应,每当一个任务完成时,就去更新并检查这些变量——这种做法略显繁琐;另一种做法是使用Rxjava操作符,但在多人维护的老项目中,如果有成员对Rxjava不太熟悉,那么贸然引入Rxjava显然也不是一个好选择;而第三种选择就是使用ConcurrentTasksManager这个简单的工具类。

ConcurrentTasksManager中有两个内部类,即执行器Executer和计数器Counter,它们各自有不同的应用场景。

Executer

Executer用来并发执行多个同步任务(对于okhttp和retrofit,同步意味着调用call.execute(...)而不是call.enque(...)),当所有任务均完成时,会通过回调通知用户。

以上面提到的欢迎页为例,先创建3个同步任务:

//(同步方式)计时3秒
Runnable timeout = new Runnable() {
    @Override
    public void run() {
        SystemClock.sleep(3000);
    }
};

//(同步方式)获取配置参数
Runnable getConfig = new Runnable() {
    @Override
    public void run() {
        Call<Config> call = ApiManager.getApiService().getConfig();
        Response<Config> configResponse = call.execute();
        ......
    }
};

//(同步方式)检查是否有更新
Runnable checkUpdate = new Runnable() {
    @Override
    public void run() {
        Call<UpdateInfo> call = ApiManager.getApiService().getUpdateInfo();
        Response<UpdateInfo> updateInfoResponse = call.execute();
        ......
    }
};

将创建好的同步任务交给Executer去执行——通过addTask(...)来添加任务,通过start(...)来并发执行添加的多个任务。当所有任务均完成时,onAllFinished方法会被调用:

ConcurrentTasksManager.newExecuter()//创建Executer。newExecuter(...)方法可接收一个线程池参数
    .addTask(timeout)
    .addTask(getConfig)
    .addTask(checkUpdate)
    .start(new ConcurrentTasksManager.Executer.OnAllFinishedListener() {
        @Override
        public void onAllFinished() {
            //全部任务均已完成,可以进行下一步操作了
        }
    });

Counter

如果有几个已经写好的异步任务(对于okhttp和retrofit,异步意味着调用call.enque(...)而不是call.execute(...)),又不想去将它们改为同步任务,那么可以使用计数器Counter来帮助简化代码。

首先是告诉Counter总共有多少个异步任务:

ConcurrentTasksManager.Counter counter = ConcurrentTasksManager.newCounter(3);//有3个异步任务需要计数

然后开始各个异步任务的执行,并在每个异步任务执行完毕时调用notifyAndCheckIfAllFinished()方法来通知counter当前任务已完成并检查是否全部的任务均已完成:

Call<Config> call = ApiManager.getApiService().getConfig();
call.enqueue(new Callback<Config>() {
    @Override
    public void onResponse(Call<Config> call, Response<Config> response) {
        ......
        if (counter.notifyAndCheckIfAllFinished()) {
            //全部任务均已完成,可以进行下一步操作了
        }
    }

    @Override
    public void onFailure(Call<Config> call, Throwable t) {
        ......
        if (counter.notifyAndCheckIfAllFinished()) {
            //全部任务均已完成,可以进行下一步操作了
        }
    }
});

工具类代码

代码未完善与优化,仅供参考。

import java.util.ArrayList;
import java.util.concurrent.ThreadPoolExecutor;

public class ConcurrentTasksManager {

    public static Executer newExecuter() {
        return new Executer(null);
    }

    public static Executer newExecuter(ThreadPoolExecutor threadPoolExecutor) {
        return new Executer(threadPoolExecutor);
    }

    public static Counter newCounter(int tasksCount) {
        return new Counter(tasksCount);
    }

//------------------------------------------------------------------------------------------

    /**
     * 执行器(并发执行多个同步任务,当所有任务均完成时,通过回调通知用户)
     */
    public static class Executer {
        private ThreadPoolExecutor threadPoolExecutor;
        private ArrayList<Runnable> tasks = new ArrayList<>();
        private int finishedCount;//已完成的任务数
        private int tasksCount;//总任务数
        private OnAllFinishedListener listener;

        public interface OnAllFinishedListener {
            void onAllFinished();
        }

        public Executer(ThreadPoolExecutor threadPoolExecutor) {
            this.threadPoolExecutor = threadPoolExecutor;
        }

        public Executer addTask(Runnable task) {
            if (task != null) {
                tasks.add(task);
            }

            return this;
        }

        public void start(OnAllFinishedListener listener) {
            if (tasks.size() == 0) return;

            this.listener = listener;
            finishedCount = 0;
            tasksCount = tasks.size();

            for (final Runnable task : tasks) {
                //包装任务
                Runnable runnable = new Runnable() {
                    @Override
                    public void run() {
                        task.run();
                        increaseAndCheck();
                    }
                };

                if (threadPoolExecutor != null) {//传入了线程池,使用线程池执行
                    threadPoolExecutor.execute(runnable);
                } else {//未传入线程池,则手动开启线程执行
                    new Thread(runnable).start();
                }
            }
        }

        /**
         * 检查是否全部任务已完成
         */
        private synchronized void increaseAndCheck() {
            finishedCount++;
            if (finishedCount == tasksCount && listener != null) {//任务已全部完成
                listener.onAllFinished();
            }
        }
    }

    /**
     * 计数器(管理多个异步任务,当所有异步任务都完成时,notifyAndCheck方法会返回true)
     */
    public static class Counter {
        private int finishedCount;//已完成的任务数
        private int tasksCount;//总任务数

        /**
         * @param tasksCount:总的任务数
         */
        public Counter(int tasksCount) {
            this.tasksCount = tasksCount;
        }

        /**
         * 通知counter当前任务已完成,并检查是否全部任务都已完成
         *
         * @return true:全部任务已完成
         */
        public synchronized boolean notifyAndCheckIfAllFinished() {
            finishedCount++;
            return (finishedCount == tasksCount);
        }
    }
}
发布了46 篇原创文章 · 获赞 38 · 访问量 4万+

猜你喜欢

转载自blog.csdn.net/al4fun/article/details/79854029