小知识:启动了Activity 的 app 至少有几个线程?

该文源于 wanandroid 上的每日一问板块(www.48989.cn)。

1

问题

想到一个非常有意思的问题:

如果 app 启动了一个 Activity,那么在这个 Activity 展示的情况下,问题来了:

1.上述场景背后至少有多少个线程?

2.每个线程具体的作用是什么?

可以先不往下滑动大概想一下,大概有多少个。

2

回答

回答人:陈小缘。

一个启动了Activity的进程会有多少个线程呢?

可以获取最顶层的线程组递归打印一下:

熟悉ThreadGroup的同学会知道,在ThreadGroup下有两个静态成员变量,分别是systemThreadGroup和mainThreadGroup,mainThreadGroup其实也是systemThreadGroup的子线程组,所以我们只需要通过反射获取到systemThreadGroup对象然后递归打印就行了,代码如下:

classMainActivity: AppCompatActivity{

overridefunonCreate(savedInstanceState: Bundle?) {

super.onCreate(savedInstanceState)

funprintThreads(threadGroup: ThreadGroup) {

"group name: ${threadGroup.name}" .logI

//本来想直接用反射获取子线程实例的,没想到threads被禁用了,好奇怪,源码里面明明没有@hide相关标识的

///threadGroup::class.get<Array<Thread?>?>(threadGroup, "threads")?.filterNotNull?.forEach { "thread name: ${it.name}".logI }

arrayOfNulls<Thread?>(threadGroup.activeCount).apply { threadGroup.enumerate( this, false) }

.filterNotNull.forEach { "thread name: ${it.name}" .logI }

threadGroup:: class. get< Array<ThreadGroup?>?> (threadGroup, "groups")?.filterNotNull?.forEach { printThreads(it) }

}

printThreads(ThreadGroup:: class. get( null, "systemThreadGroup")!!)

}

日志输出:

I/(MainActivity.kt:34) invoke: group name: system

I/(MainActivity.kt:36) invoke: thread name: Signal Catcher

I/(MainActivity.kt:36) invoke: thread name: HeapTaskDaemon

I/(MainActivity.kt:36) invoke: thread name: ReferenceQueueDaemon

I/(MainActivity.kt:36) invoke: thread name: FinalizerDaemon

I/(MainActivity.kt:36) invoke: thread name: FinalizerWatchdogDaemon

I/(MainActivity.kt:36) invoke: thread name: Profile Saver

I/(MainActivity.kt:34) invoke: group name: main

I/(MainActivity.kt:36) invoke: thread name: main

I/(MainActivity.kt:36) invoke: thread name: Jit thread pool worker thread 0

I/(MainActivity.kt:36) invoke: thread name: Binder:26573_1

I/(MainActivity.kt:36) invoke: thread name: Binder:26573_2

I/(MainActivity.kt:36) invoke: thread name: Binder:26573_3

I/(MainActivity.kt:36) invoke: thread name: Binder:26573_4

I/(MainActivity.kt:36) invoke: thread name: RenderThread

I/(MainActivity.kt:36) invoke: thread name: magnifier pixel copy result handler

I/(MainActivity.kt:36) invoke: thread name: queued-work-looper

I/(MainActivity.kt:36) invoke: thread name: DefaultDispatcher-worker-1

I/(MainActivity.kt:36) invoke: thread name: DefaultDispatcher-worker-2

I/(MainActivity.kt:36) invoke: thread name: DefaultDispatcher-worker-3

可以看到,现在进程内一共有两个线程组: system和main。

线程依次输出为:

  • Signal Catcher
  • HeapTaskDaemon
  • ReferenceQueueDaemon
  • FinalizerDaemon
  • FinalizerWatchdogDaemon
  • Profile Saver
  • main
  • Jit thread pool worker thread 0
  • Binder:26573_1
  • Binder:26573_2
  • Binder:26573_3
  • Binder:26573_4
  • RenderThread
  • magnifier pixel copy result handler
  • queued-work-looper
  • DefaultDispatcher-worker-1
  • DefaultDispatcher-worker-2
  • DefaultDispatcher-worker-3

Signal Catcher,好像挺眼熟的,但源码中搜不到,好吧,知识盲区了,我投降。

补充者:残页

Signal Catcher 是 art 中用于处理几个特殊信号的线程,比如kill -3这种方式可以dump出anr信息,就是这个线程处理的;Profile Saver这个线程则是和7.0时加的混合编译有关,设备空闲时会根据profile对部分热点方法进行编译以提高运行速度,这个profile就是这个线程负责写入的。

接着往下看,有四个Daemon线程,随便选一个全局搜一下:

它们都在一个叫Daemons的类里面。找到一篇文章:

我们经常遇到的FinalizerWatchdogDaemon TimeoutException出现了。

里面有解释这四个线程的作用:

  1. HeapTaskDaemon: 用来释放堆内存的;
  2. ReferenceQueueDaemon: 一些软、弱、虚引用的对象,当它们被回收时,会被添加到对应的ReferenceQueue中,这个操作就由ReferenceQueueDaemon来负责;
  3. FinalizerDaemon: 用来回调【即将被回收的对象】的finalize方法;
  4. FinalizerWatchdogDaemon: 监视FinalizerDaemon线程,如果在回调【即将被回收的对象】的finalize方法时超过了100_0000_0000纳秒(即10秒),那么进程会被强行kill掉;

最后一个,Profile Saver,不知道具体是做什么用的。

main线程组中的线程比较多:

  1. main: 不用讲都知道是主线程;
  2. Jit thread pool worker thread 0:不知是在哪里创建的线程池;
  3. Binder:26573_1、Binder:26573_2、Binder:26573_3、Binder:26573_4:Bind通讯线程;
  4. RenderThread:用来同步渲染BlockingGLTextureView的线程;
  5. magnifier pixel copy result handler:不知道为什么会有这个;
  6. queued-work-looper:这是一个HandlerThread(自带Looper);
  7. DefaultDispatcher-worker-123:因为我的测试Demo用了协程,这几个都是coroutines库中的线程池;

上述出现的线程个数,实在是超乎了个人的意料,正常情况下,大家只需要掌握:

1. 如何拿到当前进程的所有线程信息;

2. 掌握一些核心的线程即可:

  • main
  • Daemon相关线程
  • Binder 相关线程
  • RenderThread

这几个线程是比较容易有相关知识关联起来的,当然如果你能够掌握更多那更好了,建立起自己的知识树。

主营产品:雕刻机,金属雕刻机,电动雕刻机