void run();
/**
- Task执行时所在的线程池,可以指定,一般使用默认
*/
Executor runOn();
/**
- 存放需要先执行的task任务集合
*/
List<Class<? extends Task>> dependsOn();
/**
-
该task如果是异步任务,是否需要先等待自己完成后,
-
主线程在继续,也就是是否需要在主线程调用await的时候等待
*/
boolean needWait();
/**
- 是否在主线程执行
*/
boolean runOnMainThread();
/**
- 只能在主进程执行
*/
boolean onlyOnMainProcess();
/**
- Task主任务执行完成之后需要执行的任务
*/
Runnable getTailRunnable();
/**
- Task执行过程中的回调
*/
void setTaskCallBack(TaskCallBack callBack);
}
好了,这些基本够用了。
2.实现task接口
public abstract class Task implements ITask {
private volatile boolean mIsWaiting; // 是否正在等待
private volatile boolean mIsRunning; // 是否正在执行
private volatile boolean mIsFinished; // Task是否执行完成
private volatile boolean mIsSend; // Task是否已经被分发
// 当前Task依赖的Task数量(需要等待被依赖的Task执行完毕才能执行自己),默认没有依赖
private CountDownLatch mDepends = new CountDownLatch(dependsOn() == null ? 0 : dependsOn().size());
/**
- 依赖的Task执行完一个
*/
public void satisfy() {
mDepends.countDown();
}
/**
- 当前Task等待,让依赖的Task先执行
*/
public void waitToSatisfy() {
try {
mDepends.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
/**
-
异步线程执行的Task是否需要在被调用await的时候等待(也就是是否需要主线程等你执行完再执行),默认不需要
-
@return
*/
@Override
public boolean needWait() {
return false;
}
/**
-
当前Task依赖的Task集合(需要等待被依赖的Task执行完毕才能执行自己),默认没有依赖
-
@return
*/
@Override
public List<Class<? extends Task>> dependsOn() {
return null;
}
}
很简单,主要做的是:
1.根据dependsOn() 定义一个栅栏
很好理解,传入的task(我们的耗时任务),因为需要依赖,比如TaskA,必须得等TaskB,TaskC加载完毕才能加载TaskA,那么dependsOn()返回的就是TaskB,TaskC,也就是在TaskA中加了几个同步锁(锁的数量就是TaskA所需要依赖的Task数量),每次执行satisfy()就减少一把锁。
3.实现启动器
外部调用
TaskDispatcher instance = TaskDispatcher.createInstance();
instance.addTask(new InitBuglyTask()) // 默认添加,并发处理
.addTask(new InitBaiduMapTask()) // 在这里需要先处理了另外一个耗时任务initShareSDK,才能再处理它
.addTask(new InitJPushTask()) // 等待主线程处理完毕,再进行执行
.start();
instance.await();
构建启动器
public class TaskDispatcher {
private static Context mContext;
private static boolean sHasInit;
private static boolean sIsMainProcess;
// 存放依赖
private HashMap<Class<? extends Task>, ArrayList> mDependedHashMap = new HashMap<>();
// 存放所有的task
private List mAllTasks = new ArrayList<>();
private List<Class<? extends Task>> mClsAllTasks = new ArrayList<>();
// 调用了await的时候还没结束的且需要等待的Task队列
private List mNeedWaitTasks = new ArrayList<>();
// 已经结束了的Task队列
private volatile List<Class<? extends Task>> mFinishedTasks = new ArrayList<>(100);
// 需要在主线程中执行的Task队列
private volatile List mMainThreadTasks = new ArrayList<>();
// 保存需要Wait的Task的数量
private AtomicInteger mNeedWaitCount = new AtomicInteger();
private CountDownLatch mCountDownLatch;
/**
- 注意:每次获取的都是新对象
*/
public static TaskDispatcher getInstance(Context context) {
if (context != null) {
mContext = context;
sHasInit = true;
sIsMainProcess = Utils.isMainProcess(mContext);
}
return new TaskDispatcher();
}
/**
- 添加任务
*/
public TaskDispatcher addTask(Task task) {
if (task != null) {
// ->> 1
collectDepends(task);
// ->> 2
mAllTasks.add(task);
mClsAllTasks.add(task.getClass());
// ->> 3
if (ifNeedWait(task)) {
mNeedWaitTasks.add(task);
mNeedWaitCount.getAndIncrement();
}
}
return this;
}
/**
-
存放相关依赖信息
-
*/
private void collectDepends(Task task) {
// 如果存在依赖
if (task.dependsOn() != null && task.dependsOn().size() > 0) {
// 获取依赖
for (Class<? extends Task> cls : task.dependsOn()) {
if (mDependedHashMap.get(cls) == null) {
mDependedHashMap.put(cls, new ArrayList());
}
mDependedHashMap.get(cls).add(task);
if (mFinishedTasks.contains(cls)) {
task.satisfy();
}
}
}
}
/**
-
task 是否需要主线程等其完成再执行
-
*/
private boolean ifNeedWait(Task task) {
return !task.runOnMainThread() && task.needWait();
}
@UiThread
public void start() {
if (Looper.getMainLooper() != Looper.myLooper()) {
throw new RuntimeException(“小子,启动器必须要在主线程启动”);
}
if (mAllTasks.size() > 0) {
// 4.->> 查看被依赖的信息
printDependedMsg();
// 5.->> 拓扑排序并返回
mAllTasks = TaskSortUt
必看视频!获取2024年最新Java开发全套学习资料 备注Java
il.getSortResult(mAllTasks, mClsAllTasks);
// 6.->> 构建同步锁
mCountDownLatch = new CountDownLatch(mNeedWaitCount.get());
// 7.->> 分发task
dispatchTasks();
executeTaskMain();
}
}
/**
- 查看被依赖的信息
*/
private void printDependedMsg() {
DispatcherLog.i("needWait size : " + (mNeedWaitCount.get()));
if (false) {
for (Class<? extends Task> cls : mDependedHashMap.keySet()) {
DispatcherLog.i("cls " + cls.getSimpleName() + " " + mDependedHashMap.get(cls).size());
for (Task task : mDependedHashMap.get(cls)) {
DispatcherLog.i("cls " + task.getClass().getSimpleName());
}
}
}
}
/**
- task分发,根据设定的不同规则,分发到不同的线程
*/
private void dispatchTasks() {
for (Task task : mAllTasks) {
if (task.runOnMainThread()) {
mMainThreadTasks.add(task);
if (task.needCall()) {
task.setTaskCallBack(new TaskCallBack() {
@Override
public void call() {
TaskStat.markTaskDone();
task.setFinished(true);
satisfyChildren(task);
markTaskDone(task);
}
});
}
} else {
// 异步线程中执行,是否执行取决于具体线程池
Future future = task.runOn().submit(new DispatchRunnable(task,this));
mFutures.add(future);
}
}
/**
- 从等待队列中移除,添加进结束队列
*/
public void markTaskDone(Task task) {
// 8 ->>
if (ifNeedWait(task)) {
mFinishedTasks.add(task.getClass());
mNeedWaitTasks.remove(task);
mCountDownLatch.countDown();
mNeedWaitCount.getAndDecrement();
}
}
private void executeTaskMain() {
mStartTime = System.currentTimeMillis();
for (Task task : mMainThreadTasks) {
long time = System.currentTimeMillis();
new DispatchRunnable(task,this).run();
}
}
首先是通过getInstance()构造了一个实例对象,然后通过addTask() 添加我们的Task, 如果它不为空的话
根据上面的角标,逐一介绍
-
调用collectDepends(),遍历该task所依赖的全部task,并且以它所依赖的task为Key, 本身为Value中集合元素的一员添加进去,然后判断,该task中的依赖是否已经加载过了,如果加载过了,调用该task的satisfy()方法减该task的一把锁。
-
然后将这个task和它的class文件添加到2个集合中,方便后面使用。
-
如果该Task需要主线程等其完成再执行的话,则添加到等待队列中,等待队列计数器+1
-
打印该task所依赖的信息
-
拓扑排序,经典的算法,用于描述依赖关系的排序,在上一章节有过介绍也给出过源码,这里就不再赘述
-
这里实际上就是构建一把锁,这个锁注意并不在Task里面,Task里面的锁,注意是为了先执行依赖的Task,执行完毕,再执行自己,而这里的锁是在启动器上,其作用是让主线程等待,优先执行那些必须要先执行完毕才能让主线程继续执行完毕,再跳转页面的task
-
根据需要分发不同的线程去执行,如果是需要在主线程中执行,那就先存储起来,如果是需要在一部现场中执行,那就直接调用task.runOn()方法来异步执行耗时task,runOn()可复写,不写为默认线程池
-
如果该线程需要在主线程中执行,将它从等待队列中移除,添加进结束队列,如果该task需要主线程等待的话,主线程的同步锁-1,等待队列数-1
4.DispatchRunnable的实现
好了如何执行任务尼?
public class DispatchRunnable implements Runnable {
private Task mTask;
最后
由于文案过于长,在此就不一一介绍了,这份Java后端架构进阶笔记内容包括:Java集合,JVM、Java并发、微服务、SpringNetty与 RPC 、网络、日志 、Zookeeper 、Kafka 、RabbitMQ 、Hbase 、MongoDB、Cassandra 、Java基础、负载均衡、数据库、一致性算法、Java算法、数据结构、分布式缓存等等知识详解。
本知识体系适合于所有Java程序员学习,关于以上目录中的知识点都有详细的讲解及介绍,掌握该知识点的所有内容对你会有一个质的提升,其中也总结了很多面试过程中遇到的题目以及有对应的视频解析总结。
线程中执行,将它从等待队列中移除,添加进结束队列,如果该task需要主线程等待的话,主线程的同步锁-1,等待队列数-1
4.DispatchRunnable的实现
好了如何执行任务尼?
public class DispatchRunnable implements Runnable {
private Task mTask;
最后
由于文案过于长,在此就不一一介绍了,这份Java后端架构进阶笔记内容包括:Java集合,JVM、Java并发、微服务、SpringNetty与 RPC 、网络、日志 、Zookeeper 、Kafka 、RabbitMQ 、Hbase 、MongoDB、Cassandra 、Java基础、负载均衡、数据库、一致性算法、Java算法、数据结构、分布式缓存等等知识详解。
[外链图片转存中…(img-cW0ignor-1716402936362)]
本知识体系适合于所有Java程序员学习,关于以上目录中的知识点都有详细的讲解及介绍,掌握该知识点的所有内容对你会有一个质的提升,其中也总结了很多面试过程中遇到的题目以及有对应的视频解析总结。
[外链图片转存中…(img-JNPuWxdb-1716402936363)]
[外链图片转存中…(img-NOX5eXdJ-1716402936364)]