01 - 启动框架与调度机制
维度 A:研究
AppStartTaskDispatcher/AbsStartTask/TaskInterface启动任务调度框架的设计与机制 关注点:类继承关系、CountDownLatch 同步、主/异步并行模型、超时保护、扩展点
一、框架职责
该框架是 MiCarSettings 启动阶段的任务调度核心,在 Application.onCreate() 期间:
- 并行执行主线程任务和异步线程任务,最大化启动效率
- 时序保证:关键初始化在
onCreate()周期内完成(或超时) - 超时保护:防止异步任务卡死阻塞应用启动
- 线程安全:CountDownLatch + 主线程检查
二、类继承与接口关系
2.1 接口契约 TaskInterface
文件:base/settingsBaseLib/src/main/java/com/android/micar/settings/appstart/TaskInterface.java:5-13
public interface TaskInterface {
Executor runOnExecutor(); // 执行任务所在的线程池
boolean needWait(); // 主线程是否等待它完成
boolean isRunOnMainThread(); // 是否运行在主线程
}| 方法 | 语义 |
|---|---|
runOnExecutor() | 返回任务执行的 Executor;主线程任务返回 null |
needWait() | 是否需要主线程在 onCreate 中阻塞等待;默认 true(AbsStartTask 实现) |
isRunOnMainThread() | 标识任务线程类型,用于 ifNeedWait 判定 |
2.2 抽象基类 AbsStartTask
文件:base/settingsBaseLib/src/main/java/com/android/micar/settings/appstart/AbsStartTask.java:5
public abstract class AbsStartTask implements TaskInterface, Runnable {
private final AppStartTaskDispatcher mAppStartTaskDispatcher;
protected final Application mApplication;
public void run() {
execute(); // 1. 执行具体任务
mAppStartTaskDispatcher.markAsyncThreadStartTaskFinish(this); // 2. 自动标记完成
}
protected abstract void execute(); // 子类实现
@Override
public boolean needWait() { return true; } // 默认需要等待
}设计要点:
- 双重接口实现:
TaskInterface(契约)+Runnable(线程执行),任务对象本身即是 Runnable - run() 串联:自动在
execute()后调用markAsyncThreadStartTaskFinish()—— 子类只关心execute(),无需管同步 - 默认 needWait=true:异步任务默认被等待
2.3 两个具体实现
| 类 | 文件 | runOnExecutor | isRunOnMainThread | 说明 |
|---|---|---|---|---|
MainThreadStartTask | app/.../miauto/MainThreadStartTask.java:215-222 | null | true | 主线程同步执行 |
AsyncThreadStartTask | app/.../miauto/AsyncThreadStartTask.java:188-196 | ThreadPoolUtils.ASYNC | false | 后台线程池执行 |
2.4 ThreadPoolUtils.ASYNC 线程池
文件:base/settingsBaseLib/src/main/java/com/android/car/settings/miauto/uitls/ThreadPoolUtils.java:19-22
public final static ThreadPoolExecutor ASYNC = new ThreadPoolExecutor(
0, // 核心线程数
Integer.MAX_VALUE, // 最大线程数(无界)
60L, TimeUnit.SECONDS, // 空闲存活 60s
new SynchronousQueue<>(), // 无缓冲,直接移交
runnable -> new Thread(runnable, "ThreadPoolUtils async thread")
);特性:CachedThreadPool 变体 —— 来任务即建线程(0 核心 + SynchronousQueue 不排队),空闲 60s 回收。适合大量短期异步任务,但无界最大线程数存在线程爆炸风险(见 05-启动时序与性能全景 风险点)。
三、AppStartTaskDispatcher 调度算法
3.1 核心字段
文件:base/settingsBaseLib/src/main/java/com/android/micar/settings/appstart/AppStartTaskDispatcher.java:11-23
private static final int WAITING_TIME = 1000; // 主线程等待超时(ms)
private AbsStartTask mMainThreadStartTask; // 主线程任务
private AbsStartTask mAsyncStartTask; // 异步任务(单个)
private CountDownLatch mCountDownLatch; // 主线程阻塞同步器
private final AtomicInteger mNeedWaitCount; // 需等待的异步任务数
private long mAllTaskWaitTimeOut = WAITING_TIME; // 可配置超时3.2 start() 完整流程(:29-36)
public void start() {
if (Looper.getMainLooper() != Looper.myLooper()) {
throw new RuntimeException("The start method must be called in the main thread"); // :30-32
}
mCountDownLatch = new CountDownLatch(mNeedWaitCount.get()); // :33
dispatchAppStartTask(); // :34
await(); // :35
}为何必须主线程:dispatchAppStartTask() 会直接调 mMainThreadStartTask.run(),必须在主线程执行,否则主线程任务跑错线程。
3.3 dispatchAppStartTask() 并行派发(:82-87)
private void dispatchAppStartTask() {
mAsyncStartTask.runOnExecutor().execute(mAsyncStartTask); // :84 先提交异步(立即返回)
mMainThreadStartTask.run(); // :86 再执行主线程(同步)
}「先异步再主线程」的顺序意义:
- 异步任务提交线程池后立即返回,主线程任务才开始 → 两者真正并行
- 给线程池启动留预热时间
- 若顺序反过来(先 run 主线程),异步任务启动被推迟,并行窗口缩短
3.4 await() 超时机制(:65-79)
private void await() {
try {
if (mCountDownLatch == null) throw new RuntimeException("...start() must be called first");
if (mAllTaskWaitTimeOut == 0) mAllTaskWaitTimeOut = WAITING_TIME; // 0 值兜底
mCountDownLatch.await(mAllTaskWaitTimeOut, TimeUnit.MILLISECONDS); // 阻塞最多 1000ms
} catch (InterruptedException e) {
MLog.e(e, "AppStartTaskDispatcher await()");
}
}- 默认超时 1000ms,可通过
setAllTaskWaitTimeOut()配置 - 0 值兜底:配为 0 时自动用默认值,避免无限等待
- 超时后行为:
await()返回,主线程继续onCreate,异步任务仍在后台跑 → 下游可能访问未就绪状态
3.5 完成标记与判定
markAsyncThreadStartTaskFinish(:90-96):
public void markAsyncThreadStartTaskFinish(AbsStartTask absStartTask) {
MLog.d("Task finish:" + absStartTask.getClass().getSimpleName());
if (ifNeedWait(absStartTask)) {
mCountDownLatch.countDown(); // 释放一个等待
mNeedWaitCount.getAndDecrement(); // 原子递减
}
}ifNeedWait(:99-101):
private boolean ifNeedWait(AbsStartTask task) {
return !task.isRunOnMainThread() && task.needWait();
}主线程任务(isRunOnMainThread=true)自动排除 —— 它本就同步执行,不需要计数管理。
四、类图
classDiagram class TaskInterface { <<interface>> +runOnExecutor() Executor +needWait() boolean +isRunOnMainThread() boolean } class Runnable_ish { <<interface>> +run() void } class AbsStartTask { #mAppStartTaskDispatcher: AppStartTaskDispatcher #mApplication: Application +run() void #execute() void* +needWait() boolean } class MainThreadStartTask { #execute() void +runOnExecutor() Executor +isRunOnMainThread() boolean } class AsyncThreadStartTask { #execute() void +runOnExecutor() Executor +isRunOnMainThread() boolean } class AppStartTaskDispatcher { -WAITING_TIME: int = 1000 -mMainThreadStartTask: AbsStartTask -mAsyncStartTask: AbsStartTask -mCountDownLatch: CountDownLatch -mNeedWaitCount: AtomicInteger +start() void +setMainAppStartTask(AbsStartTask) +setAsyncStartTask(AbsStartTask) -await() void -dispatchAppStartTask() void +markAsyncThreadStartTaskFinish(AbsStartTask) -ifNeedWait(AbsStartTask) boolean } class SettingsApplication { +onCreate() void } TaskInterface <|.. AbsStartTask Runnable_ish <|.. AbsStartTask AbsStartTask <|-- MainThreadStartTask AbsStartTask <|-- AsyncThreadStartTask AppStartTaskDispatcher o-- AbsStartTask : 持有主+异步任务 SettingsApplication --> AppStartTaskDispatcher SettingsApplication --> MainThreadStartTask : 创建 SettingsApplication --> AsyncThreadStartTask : 创建
五、调度流程图
flowchart TD A["SettingsApplication.onCreate"] --> B[new AppStartTaskDispatcher] B --> C[new MainThreadStartTask] B --> D[new AsyncThreadStartTask] C --> E[setMainAppStartTask] D --> F[setAsyncStartTask] F --> G{ifNeedWait?} G -->|true| H[mNeedWaitCount.set 1] G -->|false| I[mNeedWaitCount 保持 0] E --> J[start] H --> J I --> J J --> K{主线程检查} K -->|非主线程| L[抛 RuntimeException] K -->|是主线程| M["new CountDownLatch<br/>(mNeedWaitCount.get)"] M --> N[dispatchAppStartTask] N --> O["异步任务提交线程池<br/>(立即返回)"] N --> P["主线程任务同步 run"] O --> Q["AsyncTask.execute<br/>~61ms"] Q --> R[markAsyncThreadStartTaskFinish] R --> S{ifNeedWait?} S -->|true| T[countDown] S -->|false| U[跳过] P --> V["MainTask.execute<br/>实测247ms"] T --> W["await<br/>超时1000ms"] U --> W V --> W W --> X{计数器归零 or 超时} X --> Y[onCreate 继续] classDef hot fill:#ffe1e1,stroke:#cc0000 class V hot
六、并行模型与时序
sequenceDiagram participant App as SettingsApplication participant Disp as AppStartTaskDispatcher participant Main as MainThreadStartTask participant Async as AsyncThreadStartTask participant Pool as ThreadPoolUtils.ASYNC participant Latch as CountDownLatch App->>Disp: new AppStartTaskDispatcher() App->>Main: new MainThreadStartTask(...) App->>Async: new AsyncThreadStartTask(...) App->>Disp: setMainAppStartTask(Main) App->>Disp: setAsyncStartTask(Async) Note over Disp: ifNeedWait()==true<br/>mNeedWaitCount.set(1) App->>Disp: start() Note over Disp: 检查 Looper.getMainLooper()==myLooper() Disp->>Latch: new CountDownLatch(1) Disp->>Disp: dispatchAppStartTask() par 并行启动 Disp->>Pool: execute(Async) activate Pool Pool->>Async: run() Async->>Async: execute() ~61ms Async->>Disp: markAsyncThreadStartTaskFinish() Disp->>Latch: countDown() deactivate Pool and Disp->>Main: run() activate Main Main->>Main: execute() 实测247ms deactivate Main end Disp->>Latch: await(1000ms) alt 正常(异步先完成) Latch-->>Disp: 计数器归零,立即返回 else 超时(异步>1000ms) Note over Disp: 等 1000ms 后强制返回<br/>异步仍在后台跑 end Disp-->>App: 返回,onCreate 继续
契约:「onCreate 之内执行完成」—— 但仅约束受 latch 管理的 AsyncThreadStartTask.execute() 本体,不约束其内部二次派发的任务(见 05-启动时序与性能全景「二次派发盲区」)。
七、mNeedWaitCount 硬编码为 1 的含义
文件:AppStartTaskDispatcher.java:54-62
public void setAsyncStartTask(AbsStartTask absStartTask) {
...
mAsyncStartTask = absStartTask;
if (ifNeedWait(absStartTask)) {
mNeedWaitCount.set(1); // 硬编码为 1
}
}mAsyncStartTask是单个字段,非集合 → 当前框架只支持一个异步任务- 扩展到多异步任务需改动:
mAsyncStartTask单字段 →List<AbsStartTask>set(1)→incrementAndGet()dispatchAppStartTask()单次 execute → 循环派发- API
setAsyncStartTask→addAsyncStartTask
八、设计要点与风险
优秀设计
- 接口与实现分离:TaskInterface 契约 / AbsStartTask 公共实现 / 具体类专注业务
- 自动完成标记:子类无需关心同步逻辑
- 灵活超时:可配置 + 0 值兜底
潜在风险
| 风险 | 说明 |
|---|---|
| 单异步任务限制 | mNeedWaitCount.set(1) 硬编码,扩展需改结构 |
| 异常未捕获 | AbsStartTask.run() 无 try-catch,execute() 抛异常则 markAsyncThreadStartTaskFinish 不执行 → 主线程阻塞至超时(最多 1000ms) |
| 超时无回调 | 超时后无日志/告警,难排查 |
| 无任务依赖 | 不支持任务间 DAG 依赖 |
建议改进
run()包 try-finally,异常时仍markAsyncThreadStartTaskFinish()- 超时加日志埋点
- 多任务支持(若未来需要)
九、关键源码行号索引
| 功能点 | 文件:行号 |
|---|---|
| 接口定义 | TaskInterface.java:5-13 |
| AbsStartTask 双重实现 | AbsStartTask.java:5 |
| run() 串联 | AbsStartTask.java:14-17 |
| needWait 默认 true | AbsStartTask.java:22-24 |
| WAIT_TIME=1000 | AppStartTaskDispatcher.java:13 |
| start() 线程检查 | AppStartTaskDispatcher.java:30-32 |
| CountDownLatch 初始化 | AppStartTaskDispatcher.java:33 |
| dispatchAppStartTask(先异步后主) | AppStartTaskDispatcher.java:82-87 |
| await 超时逻辑 | AppStartTaskDispatcher.java:65-79 |
| markAsyncThreadStartTaskFinish | AppStartTaskDispatcher.java:90-96 |
| ifNeedWait | AppStartTaskDispatcher.java:99-101 |
| mNeedWaitCount.set(1) | AppStartTaskDispatcher.java:60 |
| SettingsApplication 调用入口 | SettingsApplication.java:62-65 |
| ASYNC 线程池 | ThreadPoolUtils.java:19-22 |
| MainThreadStartTask.isRunOnMainThread | MainThreadStartTask.java:219-222 |
| AsyncThreadStartTask.runOnExecutor | AsyncThreadStartTask.java:188-191 |