重拾线程——子线程异常,为什么 App 会崩溃(3)

前言

在 JDK 中,若子线程发生异常崩溃,并不会阻碍主线程的运行。

fun main(args: Array<String>){
    Thread{
        throw NullPointerException("空指针异常")
    }.start()

    Thread.sleep(1000)
    println("主线程执行完成")
}

运行结果:

Exception in thread "Thread-0" java.lang.NullPointerException: 空指针异常
	at com.bjsdm.testkotlin.KotlinTestKt.main$lambda-0(KotlinTest.kt:10)
	at java.base/java.lang.Thread.run(Thread.java:829)
主线程执行完成

Process finished with exit code 0

但是,在 Android 中,假如是子线程异常崩溃了,会导致整个 App 的退出。

class MainActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        Thread{
            throw NullPointerException("空指针异常")
        }.start()

        Thread.sleep(1000)
        println("主线程执行完成")
    }

}

运行结果:

2022-05-07 17:12:09.460 4629-4655/com.bjsdm.testkotlin E/AndroidRuntime: FATAL EXCEPTION: Thread-2
    Process: com.bjsdm.testkotlin, PID: 4629
    java.lang.NullPointerException: 空指针异常
        at com.bjsdm.testkotlin.MainActivity.onCreate$lambda-0(MainActivity.kt:22)
        at com.bjsdm.testkotlin.MainActivity.$r8$lambda$B1UqpL3gHoHHpbMEdVYZWlcm70o(Unknown Source:0)
        at com.bjsdm.testkotlin.MainActivity$$ExternalSyntheticLambda0.run(Unknown Source:0)
        at java.lang.Thread.run(Thread.java:923)

这…这是为什么???

JDK DefaultUncaughtExceptionHandler

通过这篇文章《线程异常处理》我们可以了解到,对于没有捕获到的线程异常,最后会由 Thread.getDefaultUncaughtExceptionHandler() 进行统一处理,所以,我们来看看 JDK 的 DefaultUncaughtExceptionHandler 具体是哪个实现类。

val defaultUncaughtExceptionHandler = Thread.getDefaultUncaughtExceptionHandler()

Debug 看下:

在这里插入图片描述

居然是空值,难怪在 JDK 中,子线程的崩溃不会影响主线程,因为 DefaultUncaughtExceptionHandler 没有进行额外处理。

那我们来看看 Android 的 DefaultUncaughtExceptionHandler。

Android DefaultUncaughtExceptionHandler

在这里插入图片描述

em…果然是有实现类的,是 RuntimeInit 里面的 KillApplicationHandler 类。

这里我简单贴下 KillApplicationHandler 的 uncaughtException 方法的源码:

       public void uncaughtException(Thread t, Throwable e) {
            try {
				...
            } catch (Throwable t2) {
                ...
            } finally {
                // Try everything to make sure this process goes away.
                Process.killProcess(Process.myPid());
                System.exit(10);
            }
        }

相信不用我过多解释,原因就是在 finally 的代码块执行中:

                Process.killProcess(Process.myPid());
                System.exit(10);

妥妥地杀进程。难怪在 Android 中,只要子线程异常崩溃,也会导致 App 的退出。

但是,为什么要这样做?

注释是这样写的:

Handle application death from an uncaught exception. The framework catches these for the main threads, so this should only matter for threads created by applications. Before this method runs, the given instance of RuntimeInit.LoggingHandler should already have logged details (and if not it is run first).

在这里插入图片描述

只是说,是为了避免主线程出现异常时,进行的处理。

假如仅是主线程出现异常,就这样处理,确实可以理解,毕竟主线程都挂掉了,进行日志记录和杀进程是较好的方式,但是为什么在这里没有进行主线程的判断?这样就会导致即使是子线程出现异常也会导致整个 App 的崩溃。

知道答案的大佬们麻烦告知下。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值