滴滴Java三面挂了,面试官竟然问我这道线程池问题?

通常大公司三面也是技术面,不过是交叉面,意思是面试官是其他部门的负责人,这时候过不过就听天由命,看自己运气怎么样了?为什么呢?因为不同部门的负责人面试侧重点可能有很大差别,面试的问题也可能不在自己的复习范围内。

我前段时间面试了一家在线教育的独角兽公司,投递的交易部门,交叉面的时候面试官换成了运维架构组的负责人,结果是Java八股文一点没问,问的都是关于服务监控、服务治理、容器编排、持续集成等方面的,这些知识点我不能说一点不会,只是单词的拼写有点吃力。

滴滴三面的面试官说问我一道线程池的问题,我心想线程池我准备得很充分,你说是线程池有哪些状态、几种创建方式、哪些核心参数、工作原理、状态流转,我都熟,源码我也看了一些,应该难不倒我。

结果问的是,

线程池里面的代码如果抛异常了,也没有try/catch,会发生什么?

我顿时蒙了,这问的什么问题?你™不按套路出牌。

我就只能瞎猜,试着答吧。如果线程池内部出现异常了,整个线程池就毁了,任务就执行不下去了。

看着面试官的脸色,感觉回答得不对。

那就是这个线程会出问题了,线程池里面会少一个线程。

然后面试官说,今天我们就到这了,你回去等通知吧!

后来,我认真翻看了线程池的源码,才明白线程池针对异常,设计得很巧妙,功能很健壮,就是鲁棒性很强,发生任何异常它都帮你处理的好好的。

先来一段代码示例:

猜一下会输出什么?

没想到竟然是,三行日志都打印出来了,每打印一行日志就抛出一次异常。线程池真的是帮我们处理好了异常,不用我们管了?它的内部逻辑是怎么实现的呢?

我们先看一下提交线程池的execute()方法,主要作用是调用addWorker()方法,创建新线程,并把线程添加到线程池里,线程池用Set集合存储线程

private final HashSet<Worker> workers = new HashSet<Worker>();

最终会执行Worker类里面的run()方法,run()又去调用runWorker()方法,runWorker()又会调用Runnable的run()方法

再看一下退出方法processWorkerExit()逻辑

到这里已经非常清楚了,真相就是线程池里的线程出现异常后,就从线程池里删除,并新建一个线程添加到线程里。

可以验证一下:

看一下输出结果:

果然是这样,每次抛出异常,线程名称就累加一,新建了一个线程。

思考,为了捕获异常,是不是我们每次在线程池里加try/catch,其实Thread类早就给我们封装好了异常处理的方法,只要我们在线程池的线程工厂里设置一下就行了。

@FunctionalInterface
public interface UncaughtExceptionHandler {
    void uncaughtException(Thread t, Throwable e);
}

输出结果:

key=1,线程名称=Thread-0
捕获异常:手动抛出异常
key=2,线程名称=Thread-1
捕获异常:手动抛出异常
key=3,线程名称=Thread-2
捕获异常:手动抛出异常

又Get一个新知识,加油吧,少年!

举报
评论 0