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

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

首先,两个方法都是先进行一个 cas 的操作,把当前 FutureTask 的 status 字段从 NEW 修改为 COMPLETING 。


完成了状态流转的这一步:


image.png


注意这里,如果 cas 操作失败了,则不会进行任何操作。


cas 操作失败了,说明什么呢?


说明当前的状态是 CANCELLED 或者 INTERRUPTING 或者INTERRUPTED。


也就是这个任务被取消了或者被中断了。


那还设置结果干啥,没有任何卵用,对不对。


image.png


如果 cas 操作成功,接着往下看,可以看到虽然入参不一样了,但是都赋给了 outcome 变量,这个变量,在上一节的 report 方法出现过,还记得吗?能不能呼应上?


接下来就是状态接着往下流转。


set 方法表示正常结束,状态流转到 NORMAL。


setException 方法表示任务出现异常,状态流转到 EXCEPTIONAL。



所以经过 FutureTask 的 run 方法后,如果任务没有被中断或者取消,则会通过 setException 或者 set 方法完成状态的流转和 outcome 参数的设置:


image.png


而到底是调用 setException 方法还是 set 方法,取决于标号为 ① 的地方是否会抛出异常。


即取决于任务体是否会抛出异常。


假设 sayHi 方法是这样的,会抛出运行时异常:


image.png


而通过 submit 方法提交任务时写法分别如下:


如果是标号为 ① 的写法,则会进入 setException 方法。


如果是标号为 ② 的写法,则会进入 set 方法。


所以,你现在再回去看看这个题目:


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


现在是不是很清晰了。


如果子线程捕获了异常,该异常不会被封装到 Future 里面。是通过 FutureTask 的 run 方法里面的 setException 和 set 方法实现的。在这两个方法里面完成了 FutureTask 里面的 outcome 变量的设置,同时完成了从 NEW 到 NORMAL 或者 EXCEPTIONAL 状态的流转。


线程池拒绝异常


写文章的时候我突然又想到一个问题。


不论是用 submit 还是 execute 方法往线程池里面提交任务,如果由于线程池满了,导致抛出拒绝异常呢?


RejectedExecutionException 异常也是一个 RuntimeException:


image.png


那么对于这个异常,如果我们不在子线程捕获,是不是也不会打印呢?


假设你不知道这个问题,你就分析一下,从会和不会中猜一个呗。


我猜是会打印的。


因为假设让我来提供一个这样的功能,由于线程池饱和了而拒绝了新任务的提交,我肯定得给使用方一个提示。告诉他有的任务由于线程池满了而没有提交进去。


不然,使用者自己排查到这个问题后,肯定会说一声:这什么傻逼玩意,把异常给吞了?

来,搞个 Demo 验证一下:


image.png


我们定义的这个线程池最大容量是 7 个任务。


在循环体中扔 10 个比较耗时的任务进去。有 3 个任务它处理不了,那么肯定是会触发拒绝策略的。


你觉得这个程序运行后会在控制台打印异常日志吗?会打印几次呢?


看一下运行结果:


image.png


抛出了一次异常,执行完成了 7 个任务。


我们并没有捕获异常,打印堆栈信息的相关代码,那么这个异常是谁打印的?


如果你没有捕获异常,JVM 会帮你调用这个方法:


image.png


image.png


10 个任务,三次异常,完成了 7 个任务。


也不会让 JVM 触发 dispatchUncaughtException 方法了。

目录
相关文章
|
4天前
|
监控 Kubernetes Java
阿里面试:5000qps访问一个500ms的接口,如何设计线程池的核心线程数、最大线程数? 需要多少台机器?
本文由40岁老架构师尼恩撰写,针对一线互联网企业的高频面试题“如何确定系统的最佳线程数”进行系统化梳理。文章详细介绍了线程池设计的三个核心步骤:理论预估、压测验证和监控调整,并结合实际案例(5000qps、500ms响应时间、4核8G机器)给出具体参数设置建议。此外,还提供了《尼恩Java面试宝典PDF》等资源,帮助读者提升技术能力,顺利通过大厂面试。关注【技术自由圈】公众号,回复“领电子书”获取更多学习资料。
|
8天前
|
安全 Java 程序员
面试直击:并发编程三要素+线程安全全攻略!
并发编程三要素为原子性、可见性和有序性,确保多线程操作的一致性和安全性。Java 中通过 `synchronized`、`Lock`、`volatile`、原子类和线程安全集合等机制保障线程安全。掌握这些概念和工具,能有效解决并发问题,编写高效稳定的多线程程序。
49 11
|
7天前
|
Java Linux 调度
硬核揭秘:线程与进程的底层原理,面试高分必备!
嘿,大家好!我是小米,29岁的技术爱好者。今天来聊聊线程和进程的区别。进程是操作系统中运行的程序实例,有独立内存空间;线程是进程内的最小执行单元,共享内存。创建进程开销大但更安全,线程轻量高效但易引发数据竞争。面试时可强调:进程是资源分配单位,线程是CPU调度单位。根据不同场景选择合适的并发模型,如高并发用线程池。希望这篇文章能帮你更好地理解并回答面试中的相关问题,祝你早日拿下心仪的offer!
26 6
|
12天前
|
缓存 安全 算法
Java 多线程 面试题
Java 多线程 相关基础面试题
|
28天前
|
并行计算 算法 安全
面试必问的多线程优化技巧与实战
多线程编程是现代软件开发中不可或缺的一部分,特别是在处理高并发场景和优化程序性能时。作为Java开发者,掌握多线程优化技巧不仅能够提升程序的执行效率,还能在面试中脱颖而出。本文将从多线程基础、线程与进程的区别、多线程的优势出发,深入探讨如何避免死锁与竞态条件、线程间的通信机制、线程池的使用优势、线程优化算法与数据结构的选择,以及硬件加速技术。通过多个Java示例,我们将揭示这些技术的底层原理与实现方法。
83 3
|
2月前
|
存储 缓存 算法
面试官:单核 CPU 支持 Java 多线程吗?为什么?被问懵了!
本文介绍了多线程环境下的几个关键概念,包括时间片、超线程、上下文切换及其影响因素,以及线程调度的两种方式——抢占式调度和协同式调度。文章还讨论了减少上下文切换次数以提高多线程程序效率的方法,如无锁并发编程、使用CAS算法等,并提出了合理的线程数量配置策略,以平衡CPU利用率和线程切换开销。
面试官:单核 CPU 支持 Java 多线程吗?为什么?被问懵了!
|
27天前
|
缓存 安全 Java
【JavaEE】——单例模式引起的多线程安全问题:“饿汉/懒汉”模式,及解决思路和方法(面试高频)
单例模式下,“饿汉模式”,“懒汉模式”,单例模式下引起的线程安全问题,解锁思路和解决方法
|
27天前
|
Java 调度
|
4月前
|
存储 缓存 安全
【Java面试题汇总】多线程、JUC、锁篇(2023版)
线程和进程的区别、CAS的ABA问题、AQS、哪些地方使用了CAS、怎么保证线程安全、线程同步方式、synchronized的用法及原理、Lock、volatile、线程的六个状态、ThreadLocal、线程通信方式、创建方式、两种创建线程池的方法、线程池设置合适的线程数、线程安全的集合?ConcurrentHashMap、JUC
|
4月前
|
消息中间件 前端开发 NoSQL
面试官:线程池遇到未处理的异常会崩溃吗?
面试官:线程池遇到未处理的异常会崩溃吗?
92 3
面试官:线程池遇到未处理的异常会崩溃吗?

热门文章

最新文章