关于多线程中抛异常的这个面试题我再说最后一次! (1)

简介: 关于多线程中抛异常的这个面试题我再说最后一次! (1)

一道面试题


我一年前写过这篇文章《有的线程它死了,于是它变成一道面试题》,这是早期作品,遣词造句,排版行文都有一点稚嫩,但是不知咋地,还是有很多人看过。


甚至已经进入了某网红公司的面试题库里面。


微信图片_20220426223637.png



所以我后面应该会重写一下,翻新翻新,再补充一点新的东西进去。


现在先回顾一下这篇文章抛出的问题和问题的答案:


一个线程池中的线程异常了,那么线程池会怎么处理这个线程?


这个题是我遇到的一个真实的面试题,当时并没有回答的很好。然后通过上面的文章,我在源码中寻找到了答案。


先给大家看两个案例。


当执行方式是 execute 方法时,在控制台会打印堆栈异常:


image.png


当执行方式是 submit 方法时,在控制台不会打印堆栈异常:


image.png


那么怎么获取这个 submit 方法提交时的异常信息呢?


得调用返回值 future 的 get 方法:


image.png


具体原因,我在之前的文章里面详细分析过,就不赘述了,直接看结论:


image.png


然后一个读者找我聊天,说为什么他这样写,通过 future.get 方法没有抛出异常呢,和我文章里面说的不一样呢?

我说:那肯定是你操作不对,你把代码发给我看看。


image.png


然后我收到了一份这样的代码:


public class ExecutorsTest {
    public static void main(String[] args) {
        ThreadPoolExecutor executorService = new ThreadPoolExecutor(2, 2,
                30, TimeUnit.SECONDS, new ArrayBlockingQueue<>(10));
        Future future = executorService.submit(() -> {
            try {
                sayHi("submit");
            } catch (Exception e) {
                System.out.println("sayHi Exception");
                e.printStackTrace();
            }
        });
        try {
            future.get();
        } catch (Exception e) {
            System.out.println("future.get Exception");
            e.printStackTrace();
        }
    }
    private static void sayHi(String name) throws RuntimeException {
        String printStr = "【thread-name:" + Thread.currentThread().getName() + ",执行方式:" + name + "】";
        System.out.println(printStr);
        throw new RuntimeException(printStr + ",我异常啦!哈哈哈!");
    }
}


这个程序的输出结果是这样的:


image.png


我寻思这没毛病呀,这不是很正常吗?不就是应该这样输出吗?


那个哥们说:和你说的不一样啊,你说的是调用 future.get 方法的时候会抛出异常的?

我这里并没有输出“future.get Exception”,说明 future.get 方法没有抛出异常。


我回答到:你这不是把会抛出运行时异常的 sayHi 方法用 try/catch 代码块包裹起来了吗?异常在子线程里面就处理完了,也就不会封装到 Future 里面去了。你把 try/catch 代码块去掉,异常就会封装到 Future 里面了。


image.png


过了一小会,他应该是实验完了,又找过来了。


他说:牛逼呀,确实是这样的。那你的这个面试题是有问题的啊,描述不清楚,正确的描述应该是一个线程池中的线程抛出了未经捕获的运行时异常,那么线程池会怎么处理这个线程?


看到他的这个回复的时候,我竟然鼓起掌来,这届读者真是太严格了!但是他说的确实是没有错,严谨点好。


image.png


他还追问到:怎么实现的呢?为什么当 submit 方法提交任务的时候,子线程捕获了异常,future.get 方法就不抛出异常了呢?


其实听到这个问题的时候都把我干懵了。


这问法,难道你是想再抛一次异常出来?


其实大家按照正常的思维去想,都能知道如果子线程捕获了一次,future.get 方法就不应该抛出异常了。


所以,现在的问题是,这个小小的功能,在线程池里面是怎么实现的?


现在的面试题在原来的基础上再加一层:


好,你说当执行方法是 submit 的时候,如果子线程抛出未经捕获的运行时异常,将会被封装到 Future 里面?那么如果子线程捕获了异常,该异常还会封装到 Future 里面吗?是怎么实现的呢?


寻找答案-FUTURE


来,一起去源码里面寻找答案。


现在是用 submit 的方式往线程池里面提交任务,而执行的这个任务会抛出运行时异常。


对于抛出的这个异常,我们分为两种情况:


  • 子线程中捕获了异常,则调用返回的 future 的 get 方法,不会抛出异常。


  • 子线程中没有捕获异常,则调用返回的 future 的 get 方法,会抛出异常。


image.png

目录
相关文章
|
7天前
|
存储 调度 C++
【操作系统】进程与线程的区别及总结(非常非常重要,面试必考题,其它文章可以不看,但这篇文章最后的总结你必须要看,满满的全是干货......)
【操作系统】进程与线程的区别及总结(非常非常重要,面试必考题,其它文章可以不看,但这篇文章最后的总结你必须要看,满满的全是干货......)
35 1
|
7天前
|
缓存 安全 Java
Java线程面试题含答案
Java线程面试题含答案
|
7天前
|
算法 安全 网络协议
java高级面试题_java面试题大全带答案_线程面试题_java面试宝典2019
java高级面试题_java面试题大全带答案_线程面试题_java面试宝典2019
|
7天前
|
安全 算法 Java
java线程面试题_2019java面试题库
java线程面试题_2019java面试题库
|
15天前
|
安全 Java 程序员
Java基础18-一文搞懂Java多线程使用方式、实现原理以及常见面试题(二)
Java基础18-一文搞懂Java多线程使用方式、实现原理以及常见面试题(二)
33 4
|
7天前
|
Oracle Java 关系型数据库
面试知识点:notify是随机唤醒线程吗(唤醒线程顺序)?
面试知识点:notify是随机唤醒线程吗(唤醒线程顺序)?
11 0
|
8天前
|
缓存 安全 Java
java线程面试题2019最新整理
java线程面试题2019最新整理
|
15天前
|
存储 Java 调度
Android面试题之Kotlin协程到底是什么?它是线程吗?
本文探讨了协程与线程的区别,指出协程并非线程,而是轻量级的线程替代。协程轻量体现在它们共享调用栈,内存占用少,仅需几个KB。协程切换发生在用户态,避免了昂贵的内核态切换。在Kotlin中,协程通过Continuation对象实现上下文保存,允许高效并发执行,而不会像线程那样消耗大量资源。通过`runBlocking`和`launch`示例展示了协程的非阻塞挂起特性。总结来说,协程的轻量主要源于内存占用少、切换开销低和高并发能力。
18 0
|
1天前
|
存储 测试技术
【工作实践(多线程)】十个线程任务生成720w测试数据对系统进行性能测试
【工作实践(多线程)】十个线程任务生成720w测试数据对系统进行性能测试
8 0
【工作实践(多线程)】十个线程任务生成720w测试数据对系统进行性能测试
|
2天前
|
数据采集 Java Unix
10-多线程、多进程和线程池编程(2)
10-多线程、多进程和线程池编程