该文源于 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(thisfalse) }
                .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线程,随便选一个全局搜一下:

updatequeued_queued的意思_queued

它们都在一个叫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

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注