一、前语

当咱们的运用程序在 Java 层产生异常时,能够运用 Thread.setDefaultUncaughtExceptionHandle线程池面试题r 来进行大局异常的捕获,这篇文章答复了下面四个问题:

  • 在主进程中的主线程、子线程产生溃散的体现?
  • UncaughtExceptijava语言onHandler 是由谁调用的?
  • 为什么相同都是捕获了异常,主线程会呈现异常或许无法照顾,而子线程依然能够正常后续的操作?
  • 不设置 UncaughtExceptionHandlejvm调优参数r 时,系统默许的处理逻辑是什么?

二、现象

首要在 Application 中设置:

class ClientApplication: Appl线程撕裂者ication() {
companion object {
val TAG: Strijvm废物收回机制ng = ClientApplapplicationication::class.java.name
}
override fun onCreate() {
super.onCreat线程是什么意思e()
Thread.setDefaultUncaughtExceptionHandler {
thread, e -> Log.d(TAG, "thread=" + thread.id + ",throwable=" + e.message)}
}
}

2.1java根底知识点 主进java面试题程 + 主线程

class ClientActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.jvm优化onCrejava环境变量装备ate(savedInstanceStjava面试题ate)
setCont线程entView(R.layout.activjvm内存模型ity_ma线程池面试题in)
findViewById<Button>(Rapple.id.bt).setOnClickListener {
mainException()jvm是什么意思
}
}
private fun mainException() {
val exception: String? = nulJVMljvm调优参数
exception!!.length
}
}

点击按钮触发空指针异常后,程序没有当即退出,而是先打印了空指针的异常:

D/com.lee.clientapplication.ClientApplication: thread=2,throwable=null

可是咱们点击屏幕并没有任何的反应,究竟仍是抛出了运用出错的提示。

2.2 主进APP程 + 子线程

class ClientActivijava怎样读ty : AppCompatapp装置下载Activity() {
override fun onCreate(saappearvedInstanceSta线程池te: Bund线程和进程的区别是什么le?) {
super.onCreate(savedInstanceStatJavae)
setContentView(R.layout.activity_main)
findViewById<Buapproachtton>(R.id.bt).setjvm调优面试题OnClickListener {
threadException()
}
}
private fun threadException() {
thread {
val exception: String? = null
exception!!.length
}
}
}

现在咱们在子线程傍边触发空指appstore针的异常,在这种情况下,依然能够看到大局JVM捕获的打印,可是用户依然能够和页面进行交互:

2021-03-08 13:1java根本数据类型6:55.015 9516-9673/com.lee.clientapplicapproveation D/com.lejava根本数据类型e.clienta线程池面试题pplication.ClientApplication: threadjvm参数=8879,throwable=null

而假定咱们去掉了 Application 中关于异常的大局捕获,那么程序仍是会溃散的。

三、UncaughtExceptionHandler 由谁触发的

咱们能够看下官方app装置下载文档关于这个函数的说明:

Inteapplicationrface for handlers invoked when a Thread abruptly terminates due to an uncaught exception.
When a thread is about to terminate due to an uncaught exception the Java Virtual Machine will query the thread for its Uncapp装置下载aughtExceptionHandler using Thread.getUncaughtExceptionHandler() andjvm调优 will invoke the handler's uncaughtException method, passingjvm调优参数 the thread and the exception as arguments. If a threaappointmentd has not had its UncaughtEx线程的几种状况ceptionHandler explicjvm内存结构itly set, then itsjava环境变量装备 ThreadGroup object acts as its UncaughtExceptionHanjvm废物收回机制dler. If the ThreadGroup object has no special requirements fojvm参数r dealing with the exception, it can forward the invocation to the default uncaught exception handler.

当一个线程即将因不受捕获的异常即将中止时,JVM 测验会运用 Thread.getUncaughtExceptionHandler() 办法取得该线程的 UncaughtExceptionHandler 方针并调用其 uncaughtjvm调优参数Exception 办法,其java怎样读参数为该线程和异常信息。假定没有设置,那么 ThreadGroup 将会作为默许的 UncaughtExceptionHandler,假定 ThreadGroup 也没有处理,那么会选用 default uncaught exception hjvm是什么意思andler。

由此可见 UncaughtExceptionHandler 是由虚拟机通线程过 dispatchUncappstoreaughtException 触发的,appstore线程安全用链为:java怎样读

  • UncaughtExappointmentceptionHandler:线程的java面试题成员变量,假定没有设置 UncaughtExceptionHandler,那么会调用 group 成员处理。
public class Thread implejvm调优面试题ments Runnable {
public UncaughtExceptionHandler getUncaughtExceptionHajava环境变量装备ndler() {
return u线程安全ncaughtExceptiojvm参数nHandler != null ?
uncaughtExceptionHandler : group;
}
public final voiJVMd dispatchUncaug线程和进程的区别是什么htException(Throwable e) {
getUncaughtExceptionHandler().uncaughtException(this, e);
}
}
  • ThreadGroup:group 也是完成了 UncaughtExcjava模拟器ep线程的几种状况tionHandler 接口,内部逻辑是先托付其 parjvm调优面试题ent 处理,直到 parent 为空时,究竟 parent 为空时才会走到调用 sDefaultUncaughtExceptionHandler。
publicjvm参数 classjava根本数据类型 ThreadGroup implements Thread.Unca线程池面试题ughtExceptio线程和进程的区别是什么nHandler {
public void uncaughtException(Thread t, Throwable e) {
if (pajava怎样读rent != null) {
parent.uncaughtExceappreciateptiappointmenton(t, e);
} else {
Thread.UncaughtExceptionHandler ueh =
Thread.getDefaultUncaughtExceptionHandler();
ifjava环境变量装备 (ueh != null) {
ueh.uncaughtException(t, e);
} else if (!(e instanceof ThreadDeath)) {
System.err.p线程同步rint("Exception in thread ""
+ t.getName() + "" ");
e.线程池的创立方式有几种printStacjvm调优参数kTrace(Sysapplicationtem.err);
}
}
}
}
  • sDefaultUncaughtExceptionHandler:线程的静态成员变量,用于处理该进程中的悉数线程,也便是咱们在上一部分所举的比如。

这儿说明一下:

  • 关于子线程来说,其 ThreadGrojvm优化up 为主线程 [name=main, maxpri线程池面试题=10]
  • 主线程的 parent 也是一个 ThreadGroup [najava编译器me=syst线程是什么意思em, max线程的几种状况pri=10],其 parent 为 null。

流程图如下:
UncaughtExceptionHandler 小结

四、为什么主线程会呈现无法照顾,而子线程不会

首要咱们要知道运用程序和系统间的交互根据的是 音讯驱动 的模型:

  • 事情源经过 Binder 调用传递到运用程序进程后,会将处理的音讯加入到音讯行列傍边,例如按键、触摸、制作等。
  • 运用程序再不断地从音讯行列中取出音讯进行处理。

运用程序是线程同步在其主线程进行处理这些音讯的,这儿是经过一个无限循环,即 Looper.loop(),没有音讯时休眠,有音讯时被唤醒去处理音讯,因而主线程不能够完毕,完毕了就无法处理音讯了。

即 ActivityThread.main 办法:

public static void main(String[] args) {
Looper.prepareMainLooper();
Looper.loop(jvm废物收回机制);
throw new RuntimeException("Main thread loop unexpectedlyjava根本数据类型 exi线程池的创立方式有几种ted");
}

由于主线程完毕了,那么就无法及时处理 AMS/WMS 发送的音讯或许给予反应approach,就会触发体appreciate系调用差错或许 ANR。

而子线程由于不触及这些,完毕就完毕了,和任务履行完了没什么差异,因而也就不会产生异常。jvm调优

无、默许的处application理规则

假定咱们没有设置自定义的 handler,那么系统是有自己一套默许的处理逻辑的,这段代码在运用进程启动时,即 RuntimeInit#commonInit 中:

protected static final void commonInit() {
LoggingHandler loggingHandler = new LoggingHandler();
RuntimeHooks.setUncaughtExceptionPreHajvm参数ndle线程是什么意思r(loggingHandler);
Thread.setDefaultUncaughtExceptionHandler(new KillApplicationHjavaeeandler(loggingHandler));
}

KillApplicationHandler 会经过 Binder 调用到 AMS 端进行异常信息的记载,终究会调用 Process.killProcesappointments(Process.myPid()) & System.exit(10) 完毕掉运用进程,这也是为什么在没有设置自定的 handler 情况下,jvm内存模型子线程傍边产生异常会导致运用程序退出。