APP性能优化系列-自定义启动器(三)

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 = TaskSortUtil.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, 如果它不为空的话

根据上面的角标,逐一介绍

  1. 调用collectDepends(),遍历该task所依赖的全部task,并且以它所依赖的task为Key, 本身为Value中集合元素的一员添加进去,然后判断,该task中的依赖是否已经加载过了,如果加载过了,调用该task的satisfy()方法减该task的一把锁。

  2. 然后将这个task和它的class文件添加到2个集合中,方便后面使用。

  3. 如果该Task需要主线程等其完成再执行的话,则添加到等待队列中,等待队列计数器+1

  4. 打印该task所依赖的信息

  5. 拓扑排序,经典的算法,用于描述依赖关系的排序,在上一章节有过介绍也给出过源码,这里就不再赘述

  6. 这里实际上就是构建一把锁,这个锁注意并不在Task里面,Task里面的锁,注意是为了先执行依赖的Task,执行完毕,再执行自己,而这里的锁是在启动器上,其作用是让主线程等待,优先执行那些必须要先执行完毕才能让主线程继续执行完毕,再跳转页面的task

  7. 根据需要分发不同的线程去执行,如果是需要在主线程中执行,那就先存储起来,如果是需要在一部现场中执行,那就直接调用task.runOn()方法来异步执行耗时task,runOn()可复写,不写为默认线程池

  8. 如果该线程需要在主线程中执行,将它从等待队列中移除,添加进结束队列,如果该task需要主线程等待的话,主线程的同步锁-1,等待队列数-1

4.DispatchRunnable的实现


好了如何执行任务尼?

public class DispatchRunnable implements Runnable {

private Task mTask;

private TaskDispatcher mTaskDispatcher;

public DispatchRunnable(Task task) {

this.mTask = task;

}

public DispatchRunnable(Task task,TaskDispatcher dispatcher) {

this.mTask = task;

this.mTaskDispatcher = dispatcher;

}

@Override

public void run() {

Process.setThreadPriority(mTask.priority());

long startTime = System.currentTimeMillis();

mTask.setWaiting(true);

mTask.waitToSatisfy();

long waitTime = System.currentTimeMillis() - startTime;

startTime = System.currentTimeMillis();

// 执行Task

mTask.setRunning(true);

mTask.run();

// 执行Task的尾部任务

Runnable tailRunnable = mTask.getTailRunnable();

if (tailRunnable != null) {

tailRunnable.run();

}

if (!mTask.needCall() || !mTask.runOnMainThread()) {

printTaskLog(startTime, waitTime);

TaskStat.markTaskDone();

mTask.setFinished(true);

if(mTaskDispatcher != null){

mTaskDispatcher.satisfyChildren(mTask);

// --> 8

mTaskDispatcher.markTaskDone(mTask);

}

}

TraceCompat.endSection();

}

}

复制代码

好了,是不是很简单? 优先执行需要依赖的Task, 然后再执行自己,等都执行完毕后,调用mTaskDispatcher.markTaskDone(mTask); 将该task从等待队列中移除,添加进结束队列,如果该task需要主线程等待的话,主线程的同步锁-1,等待队列数-1

再看下我们自己的task

public class InitJPushTask extends Task {

@Override

public boolean needWait() {

return true;

}

@Override

public List<Class<? extends Task>> dependsOn() {

List<Class<? extends Task>> tasks = new ArrayList<>();

tasks.add(GetDeviceIdTask.class);

return tasks;

}

@Override
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数Java工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

如果你觉得这些内容对你有帮助,可以扫码获取!!(备注:Java)

最后

一次偶然,从朋友那里得到一份“java高分面试指南”,里面涵盖了25个分类的面试题以及详细的解析:JavaOOP、Java集合/泛型、Java中的IO与NIO、Java反射、Java序列化、Java注解、多线程&并发、JVM、Mysql、Redis、Memcached、MongoDB、Spring、Spring Boot、Spring Cloud、RabbitMQ、Dubbo 、MyBatis 、ZooKeeper 、数据结构、算法、Elasticsearch 、Kafka 、微服务、Linux。

这不,马上就要到招聘季了,很多朋友又开始准备“金三银四”的春招啦,那我想这份“java高分面试指南”应该起到不小的作用,所以今天想给大家分享一下。

image

请注意:关于这份“java高分面试指南”,每一个方向专题(25个)的题目这里几乎都会列举,在不看答案的情况下,大家可以自行测试一下水平 且由于篇幅原因,这边无法展示所有完整的答案解析
《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!
a)**

[外链图片转存中…(img-l3irOW4F-1713811168496)]

最后

一次偶然,从朋友那里得到一份“java高分面试指南”,里面涵盖了25个分类的面试题以及详细的解析:JavaOOP、Java集合/泛型、Java中的IO与NIO、Java反射、Java序列化、Java注解、多线程&并发、JVM、Mysql、Redis、Memcached、MongoDB、Spring、Spring Boot、Spring Cloud、RabbitMQ、Dubbo 、MyBatis 、ZooKeeper 、数据结构、算法、Elasticsearch 、Kafka 、微服务、Linux。

这不,马上就要到招聘季了,很多朋友又开始准备“金三银四”的春招啦,那我想这份“java高分面试指南”应该起到不小的作用,所以今天想给大家分享一下。

[外链图片转存中…(img-nZ63sdGA-1713811168496)]

请注意:关于这份“java高分面试指南”,每一个方向专题(25个)的题目这里几乎都会列举,在不看答案的情况下,大家可以自行测试一下水平 且由于篇幅原因,这边无法展示所有完整的答案解析
《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值