该文源于 wanandroid 上的每日一问板块。
问题
想到一个非常有意思的问题:
如果 app 启动了一个 Activity,那么在这个 Activity 展示的情况下,问题来了:
1.上述场景背后至少有多少个线程?
2.每个线程具体的作用是什么?
可以先不往下滑动大概想一下,大概有多少个。
回答
回答人:陈小缘。
一个启动了Activity的进程会有多少个线程呢?
可以获取最顶层的线程组递归打印一下:
熟悉ThreadGroup的同学会知道,在ThreadGroup下有两个静态成员变量,分别是systemThreadGroup和mainThreadGroup,mainThreadGroup其实也是systemThreadGroup的子线程组,所以我们只需要通过反射获取到systemThreadGroup对象然后递归打印就行了,代码如下:
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
fun printThreads(threadGroup: ThreadGroup) {
"group name: ${threadGroup.name}".logI()
//本来想直接用反射获取子线程实例的,没想到threads被禁用了,好奇怪,源码里面明明没有@hide相关标识的
///threadGroup::class.get<Array?>(threadGroup, "threads")?.filterNotNull()?.forEach { "thread name: ${it.name}".logI() }
arrayOfNulls(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,好像挺眼熟的,但源码中搜不到,好吧,知识盲区了,我投降。
补充者:残页
Signal Catcher 是 art 中用于处理几个特殊信号的线程,比如kill -3这种方式可以dump出anr信息,就是这个线程处理的;Profile Saver这个线程则是和7.0时加的混合编译有关,设备空闲时会根据profile对部分热点方法进行编译以提高运行速度,这个profile就是这个线程负责写入的。
接着往下看,有四个Daemon线程,随便选一个全局搜一下:
它们都在一个叫Daemons的类里面。找到一篇文章:
我们经常遇到的FinalizerWatchdogDaemon TimeoutException出现了。
里面有解释这四个线程的作用:
HeapTaskDaemon:用来释放堆内存的;
ReferenceQueueDaemon:一些软、弱、虚引用的对象,当它们被回收时,会被添加到对应的ReferenceQueue中,这个操作就由ReferenceQueueDaemon来负责;
FinalizerDaemon:用来回调【即将被回收的对象】的finalize方法;
FinalizerWatchdogDaemon:监视FinalizerDaemon线程,如果在回调【即将被回收的对象】的finalize方法时超过了100_0000_0000纳秒(即10秒),那么进程会被强行kill掉;
最后一个,Profile Saver,不知道具体是做什么用的。
main线程组中的线程比较多:
main:不用讲都知道是主线程;
Jit thread pool worker thread 0:不知是在哪里创建的线程池;
Binder:26573_1、Binder:26573_2、Binder:26573_3、Binder:26573_4:Bind通讯线程;
RenderThread:用来同步渲染BlockingGLTextureView的线程;
magnifier pixel copy result handler:不知道为什么会有这个;
queued-work-looper:这是一个HandlerThread(自带Looper);
DefaultDispatcher-worker-123:因为我的测试Demo用了协程,这几个都是coroutines库中的线程池;
上述出现的线程个数,实在是超乎了个人的意料,正常情况下,大家只需要掌握:
1. 如何拿到当前进程的所有线程信息;
2. 掌握一些核心的线程即可:
这几个线程是比较容易有相关知识关联起来的,当然如果你能够掌握更多那更好了,建立起自己的知识树。
限 时 特 惠: 本站每日持续更新海量各大内部创业教程,一年会员只需98元,全站资源免费下载 点击查看详情
站 长 微 信: lzxmw777