01 - 启动框架与调度机制

维度 A:研究 AppStartTaskDispatcher / AbsStartTask / TaskInterface 启动任务调度框架的设计与机制 关注点:类继承关系、CountDownLatch 同步、主/异步并行模型、超时保护、扩展点


一、框架职责

该框架是 MiCarSettings 启动阶段的任务调度核心,在 Application.onCreate() 期间:

  1. 并行执行主线程任务和异步线程任务,最大化启动效率
  2. 时序保证:关键初始化在 onCreate() 周期内完成(或超时)
  3. 超时保护:防止异步任务卡死阻塞应用启动
  4. 线程安全: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 两个具体实现

文件runOnExecutorisRunOnMainThread说明
MainThreadStartTaskapp/.../miauto/MainThreadStartTask.java:215-222nulltrue主线程同步执行
AsyncThreadStartTaskapp/.../miauto/AsyncThreadStartTask.java:188-196ThreadPoolUtils.ASYNCfalse后台线程池执行

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 再执行主线程(同步)
}

「先异步再主线程」的顺序意义:

  1. 异步任务提交线程池后立即返回,主线程任务才开始 → 两者真正并行
  2. 给线程池启动留预热时间
  3. 若顺序反过来(先 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单个字段,非集合 → 当前框架只支持一个异步任务
  • 扩展到多异步任务需改动:
    1. mAsyncStartTask 单字段 → List<AbsStartTask>
    2. set(1)incrementAndGet()
    3. dispatchAppStartTask() 单次 execute → 循环派发
    4. API setAsyncStartTaskaddAsyncStartTask

八、设计要点与风险

优秀设计

  • 接口与实现分离: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 默认 trueAbsStartTask.java:22-24
WAIT_TIME=1000AppStartTaskDispatcher.java:13
start() 线程检查AppStartTaskDispatcher.java:30-32
CountDownLatch 初始化AppStartTaskDispatcher.java:33
dispatchAppStartTask(先异步后主)AppStartTaskDispatcher.java:82-87
await 超时逻辑AppStartTaskDispatcher.java:65-79
markAsyncThreadStartTaskFinishAppStartTaskDispatcher.java:90-96
ifNeedWaitAppStartTaskDispatcher.java:99-101
mNeedWaitCount.set(1)AppStartTaskDispatcher.java:60
SettingsApplication 调用入口SettingsApplication.java:62-65
ASYNC 线程池ThreadPoolUtils.java:19-22
MainThreadStartTask.isRunOnMainThreadMainThreadStartTask.java:219-222
AsyncThreadStartTask.runOnExecutorAsyncThreadStartTask.java:188-191