线程优化

线程优化

Anrdoid 中的线程模型

线程调度原理
  • 任一时刻,一个 CPU 核心只有一个线程处于运行状态
  • 多线程并发,轮流获取 CPU 使用权
线程调度模型
  • 分时调度模型:轮流获取、均分 CPU
  • 抢占式调度模型:谁抢到谁使用,优先级高的线程抢到的概率更高。所以最直接的干预就是设置线程优先级
Android 中采用抢占式调度模型
  1. nice 值,【注意】nice值不是优先级

    Process 中定义,值越小优先级越高,默认时 THREAD_PRIORITY_DEFAUT = 0

    1
    Process.setThreadPriority()
  2. priority优先级

    线程优先级,值越大优先级越高

    1
    new Therad().setPriority()
  3. cgroup

    更严格的群组调度策略,如果低优先级的线程比较多而高优先级的线程较少,同样会造成高优先级线程饥饿,所以分前台 group 和后台 group,保证前台线程可以获取更多的 CPU 时间片

注意事项
  • 线程过多会导致 CPU 频繁切换,降低线程运行效率,还有可能出现线程饥饿(长时间没有得到执行)
  • 优先级具有继承性
  • 正确认识任务重要性决定优先级
  • 线程必须命名,以定位归属
  • 注意区分 IO 密集型和 CPU 密集型任务

Android 中异步的方式

  • 直接创建 Thread
    • 不易复用,频繁创建及销毁开销大
    • 复杂场景不易使用,比如要执行一个定时的任务,能实现,但不易使用
  • HandlerThread
    • 自带消息循环的线程,串行执行任务,适合长时间运行,不断从队列中获取任务
  • IntentService
    • 继承自 Service 在内部创建 HandlerThread,异步不占用主线程
    • 因为是 Service 所以优先级较高,不易被系统 Kill
  • AsyncTask
    • Android 提供的异步工具类,内部的实现也是线程池
    • 无需自己处理线程切换
  • 线程池【推荐】
    • 易复用,减少频繁创建、销毁的时间
    • 功能强大:定时、任务队列、并发数控制等
  • RxJava 【推荐】
    • 完善的线程集合,区分 IOComputation

线程使用准则

  • 提供基础线程池供各个业务线使用
    • 避免各自维护线程池,导致线程数过多
    • 同时方便监控线程的调度情况
  • 需要区分不同业务的异步方式,如 IOComputation
    • CPU密集型线程池大小与CPU核心数相近
    • 优先级低,长时间执行可以考虑使用 HandlerThread
    • 定时任务,可以考虑使用线程池
  • 创建线程必须命名
    • 方便定位线程归属
    • 运行期 Thread.currentThread().setName() 来修改名字,使用完后再修改回原理的名字
  • 关键异步任务监控
  • 重视优先级设置
    • Process.setThreadPriority()
    • 可以设置多次

锁定线程创建者

项目变大之后,项目源码、三方库、aar中都有创建线程,线程比较多,那就需要对线程进行收敛,那就需要知道线程是那里创建,是否足够合理。所有的异步方式,都会走到 new Thread 这个构造方法里,可以在这里获取调用栈的信息来锁定线程创建者

通过 Hook Thread 的构造函数,来定位创建者,下面通过 ART-Hook 的方式来 Hook 构造函数

1
2
3
4
5
6
7
8
DexposedBridge.hookAllConstructors(Thread.class, new XC_MethodHook() {
@Override
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
super.afterHookedMethod(param);
Thread thread = (Thread) param.thisObject;
LogUtils.i(thread.getName()+" stack "+Log.getStackTraceString(new Throwable()));
}
});