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

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

两种情况都和 future.get 方法有关,那我们就从这个方法的源码入手。


这个 Future 是一个接口:


image.png


而这个接口有非常多的实现类。我们找哪个实现类呢?


就是下面这个实现类:


java.util.concurrent.FutureTask


至于是怎么找到它的,你慢慢往后看就知道了。


先看看 FutureTask 的 get 方法:


image.png


get 方法的逻辑很简单,首先判断当前状态是否已完成,如果不是,则进入等待,如果是,则进入 report 方法。


一进 get 方法,我们就看到了 state 这个东西,这是 FutureTask 里面一个非常重要的东西:


image.png


所以,一目了然,一个任务的终态有四种:NORMAL、EXCEPTIONAL、CANCELLED、INTERRUPTED。


而我们主要关心 NORMAL、EXCEPTIONAL。


所以再回头看看 get 方法:


image.png


如果当前状态是小于 COMPLEING 的。


也就是当前状态只能是 NEW 或者 COMPLEING,总之就是任务还没有完成。所以进入 awaitDone 方法。这个方法不是本文关心的地方,接着往下看。


程序能往下走,说明当前的状态肯定是下面圈起来的状态中的某一个:


image.png


这个方法是干啥的?


注解说的很清楚了:对于已经完成了的 task,返回其结果或者抛出异常。


这里面的逻辑就很简单了,把 outcome 变量赋值给 x 。


然后判断当前状态,如果是 NORMAL,即 2,说明正常完成,直接返回 x。


如果是大于等于 CANCELLED,即大于等于 4 ,即这几种状态,就抛出 CancellationException。


剩下的情况就抛出 ExecutionException。


image.png


而这个“剩下的情况”是什么情况?


不就只剩下一个 EXCEPTIONAL 的情况了。


所以,经过前面的描述,我们可以总结一下。


当 FutureTask 的 status 为 NORMAL 时正常返回结果,当 status 为 EXCEPTIONAL 时抛出异常。


而当终态为 NORMAL 或者 EXCEPTIONAL 时,按照注释描述,状态的流程只能是这样的:


image.png



那么到底是不是这样的呢?


这就需要我们去线程池里面验证一下了。


寻找答案-线程池


先回答上一节的一个问题:我怎么知道是看 Future 这个接口的 FutureTask 这个实现类的:


image.png


image.png


可以看到,FutureTask 的构造方法里面默认了状态为 NEW。


然后直接在 runWorker 方法的 task.run 方法处打上断点:


image.png


这个 task 是一个 FutureTask,所以 run 方法其实是 FutureTask 的 run 方法。


跟着断点进去之后,就是 FutureTask 的 run 方法:


image.png


答案都藏在这个方法里面。


java.util.concurrent.FutureTask#run


标号为 ① 的地方是执行我们的任务,call 的就是示例代码里面的 sayHi 方法。


如果 sayHi 方法没有捕获运行时异常,则会在标号为 ② 的这个 catch 里面被捕获。然后执行标号为 ② 的这个代码。


如果 sayHi 方法捕获了运行时异常,则会进入标号为 ③ 的这个逻辑里面。


我们分别看一下标号为 ② 和 ③ 的逻辑:


image.png


目录
相关文章
|
2天前
|
缓存 安全 算法
Java 多线程 面试题
Java 多线程 相关基础面试题
|
18天前
|
并行计算 算法 安全
面试必问的多线程优化技巧与实战
多线程编程是现代软件开发中不可或缺的一部分,特别是在处理高并发场景和优化程序性能时。作为Java开发者,掌握多线程优化技巧不仅能够提升程序的执行效率,还能在面试中脱颖而出。本文将从多线程基础、线程与进程的区别、多线程的优势出发,深入探讨如何避免死锁与竞态条件、线程间的通信机制、线程池的使用优势、线程优化算法与数据结构的选择,以及硬件加速技术。通过多个Java示例,我们将揭示这些技术的底层原理与实现方法。
71 3
|
2月前
|
存储 缓存 算法
面试官:单核 CPU 支持 Java 多线程吗?为什么?被问懵了!
本文介绍了多线程环境下的几个关键概念,包括时间片、超线程、上下文切换及其影响因素,以及线程调度的两种方式——抢占式调度和协同式调度。文章还讨论了减少上下文切换次数以提高多线程程序效率的方法,如无锁并发编程、使用CAS算法等,并提出了合理的线程数量配置策略,以平衡CPU利用率和线程切换开销。
面试官:单核 CPU 支持 Java 多线程吗?为什么?被问懵了!
|
17天前
|
缓存 安全 Java
【JavaEE】——单例模式引起的多线程安全问题:“饿汉/懒汉”模式,及解决思路和方法(面试高频)
单例模式下,“饿汉模式”,“懒汉模式”,单例模式下引起的线程安全问题,解锁思路和解决方法
|
17天前
|
Java 调度
|
4月前
|
存储 缓存 安全
【Java面试题汇总】多线程、JUC、锁篇(2023版)
线程和进程的区别、CAS的ABA问题、AQS、哪些地方使用了CAS、怎么保证线程安全、线程同步方式、synchronized的用法及原理、Lock、volatile、线程的六个状态、ThreadLocal、线程通信方式、创建方式、两种创建线程池的方法、线程池设置合适的线程数、线程安全的集合?ConcurrentHashMap、JUC
|
4月前
|
消息中间件 前端开发 NoSQL
面试官:线程池遇到未处理的异常会崩溃吗?
面试官:线程池遇到未处理的异常会崩溃吗?
89 3
面试官:线程池遇到未处理的异常会崩溃吗?
|
4月前
|
消息中间件 前端开发 NoSQL
面试官:如何实现线程池任务编排?
面试官:如何实现线程池任务编排?
46 1
面试官:如何实现线程池任务编排?
|
5月前
|
Java
【多线程面试题二十五】、说说你对AQS的理解
这篇文章阐述了对Java中的AbstractQueuedSynchronizer(AQS)的理解,AQS是一个用于构建锁和其他同步组件的框架,它通过维护同步状态和FIFO等待队列,以及线程的阻塞与唤醒机制,来实现同步器的高效管理,并且可以通过实现特定的方法来自定义同步组件的行为。
【多线程面试题二十五】、说说你对AQS的理解
|
5月前
|
消息中间件 缓存 算法
Java多线程面试题总结(上)
进程和线程是操作系统管理程序执行的基本单位,二者有明显区别: 1. **定义与基本单位**:进程是资源分配的基本单位,拥有独立的内存空间;线程是调度和执行的基本单位,共享所属进程的资源。 2. **独立性与资源共享**:进程间相互独立,通信需显式机制;线程共享进程资源,通信更直接快捷。 3. **管理与调度**:进程管理复杂,线程管理更灵活。 4. **并发与并行**:进程并发执行,提高资源利用率;线程不仅并发还能并行执行,提升执行效率。 5. **健壮性**:进程更健壮,一个进程崩溃不影响其他进程;线程崩溃可能导致整个进程崩溃。
61 2