面试官:线程池遇到未处理的异常会崩溃吗?

news/2024/9/19 17:35:38/文章来源:https://www.cnblogs.com/vipstone/p/18412245

首先,这个问题考察的是你对线程池 execute 方法和 submit 方法的理解,在 Java 线程池的使用中,我们可以通过 execute 方法或 submit 方法给线程池添加任务,但如果线程池中的程序在执行时,遇到了未处理的异常会怎么呢?接下来我们一起来看。

1.execute方法

execute 方法用于提交一个不需要返回值的任务给线程池执行,它接收一个 Runnable 类型的参数,并且不返回任何结果。

它的使用示例代码如下:

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;public class ExecuteDemo {public static void main(String[] args) {ExecutorService executor = Executors.newFixedThreadPool(5);// 使用 execute 方法提交任务executor.execute(new Runnable() {@Overridepublic void run() {System.out.println("Task running in " + Thread.currentThread().getName());try {// 模拟任务执行Thread.sleep(2000);} catch (InterruptedException e) {Thread.currentThread().interrupt();System.err.println("Task was interrupted");}System.out.println("Task finished");}});// 关闭线程池executor.shutdown();}
}

2.submit方法

submit 方法用于提交一个需要返回值的任务(Callable 对象),或者不需要返回值但希望获取任务状态的任务(Runnable 对象,但会返回一个 Future 对象)。

它接收一个 Callable 或 Runnable 类型的参数,并返回一个 Future 对象,通过该对象可以获取任务的执行结果或检查任务的状态。

2.1 提交Callable任务

示例代码如下:

import java.util.concurrent.Callable;  
import java.util.concurrent.ExecutionException;  
import java.util.concurrent.ExecutorService;  
import java.util.concurrent.Executors;  
import java.util.concurrent.Future;  public class SubmitCallableDemo {  public static void main(String[] args) {  // 创建一个固定大小的线程池  ExecutorService executorService = Executors.newFixedThreadPool(2);  // 提交一个 Callable 任务给线程池执行  Future<String> future = executorService.submit(new Callable<String>() {  @Override  public String call() throws Exception {  Thread.sleep(2000); // 模拟任务执行时间  return "Task's execution result";  }  });  try {  // 获取任务的执行结果  String result = future.get();  System.out.println("Task result: " + result);  } catch (InterruptedException | ExecutionException e) {  e.printStackTrace();  }  // 关闭线程池  executorService.shutdown();  }  
}

2.2 提交Runnable任务

提交 Runnable 任务并获取 Future 对象,示例代码如下:

import java.util.concurrent.ExecutorService;  
import java.util.concurrent.Executors;  
import java.util.concurrent.Future;  public class SubmitRunnableDemo {  public static void main(String[] args) {  // 创建一个固定大小的线程池  ExecutorService executorService = Executors.newFixedThreadPool(2);  // 提交一个 Runnable 任务给线程池执行,并获取一个 Future 对象  Future<?> future = executorService.submit(new Runnable() {  @Override  public void run() {  System.out.println("Task is running in thread: " + Thread.currentThread().getName());  }  });  // 检查任务是否完成(这里只是为了示例,实际使用中可能不需要这样做)  if (future.isDone()) {  System.out.println("Task is done");  } else {  System.out.println("Task is not done yet");  }  // 关闭线程池  executorService.shutdown();  }  
}

3.遇到未处理异常

线程池遇到未处理的异常执行行为和添加任务的方法有关,也就是说 execute 方法和 submit 方法在遇到未处理的异常时执行行为是不一样的

3.1 execute方法遇到未处理异常

示例代码如下:

import java.util.concurrent.*;public class ThreadPoolExecutorExceptionTest {public static void main(String[] args)  {ThreadPoolExecutor executor = new ThreadPoolExecutor(1,1,1000,TimeUnit.MILLISECONDS,new ArrayBlockingQueue<Runnable>(100));// 添加任务一executor.execute(() -> {String tName = Thread.currentThread().getName();System.out.println("线程名:" + tName);throw new RuntimeException("抛出异常");});// 添加任务二executor.execute(() -> {String tName = Thread.currentThread().getName();System.out.println("线程名:" + tName);throw new RuntimeException("抛出异常");});}
}

以上程序的执行结果如下:

从上述结果可以看出,线程池中的核心和最大线程数都为 1 的情况下,到遇到未处理的异常时,执行任务的线程却不一样,这说明了:当使用 execute 方法时,如果遇到未处理的异常,会抛出未捕获的异常,并将当前线程进行销毁

3.2 submit方法遇到未处理异常

然而,当我们将线程池的添加任务方法换成 submit() 之后,执行结果又完全不同了,以下是示例代码:

import java.util.concurrent.*;public class ThreadPoolExecutorExceptionTest {public static void main(String[] args)  {ThreadPoolExecutor executor = new ThreadPoolExecutor(1,1,1000,TimeUnit.MILLISECONDS,new ArrayBlockingQueue<Runnable>(100));// 添加任务一Future<?> future = executor.submit(() -> {String tName = Thread.currentThread().getName();System.out.println("线程名:" + tName);throw new RuntimeException("抛出异常");});// 添加任务二Future<?> future2 =executor.submit(() -> {String tName = Thread.currentThread().getName();System.out.println("线程名:" + tName);throw new RuntimeException("抛出异常");});try {future.get();} catch (Exception e) {System.out.println("遇到异常:"+e.getMessage());}try {future2.get();} catch (Exception e) {System.out.println("遇到异常:"+e.getMessage());}}
}

以上程序的执行结果如下:

从上述结果可以看出,submit 方法遇到未处理的异常时,并将该异常封装在 Future 的 get 方法中,而不会直接影响执行任务的线程,这样线程就可以继续复用了

小结

线程池在遇到未处理的异常时,不同添加任务的方法的执行行为是不同的:

  • execute 方法:遇到未处理的异常,线程会崩溃,并打印异常信息。
  • submit 方法:遇到未处理的异常,线程本身不会受到影响(线程可以复用),只是将异常信息封装到返回的对象 Future 中。

课后思考

为什么遇到未处理的异常时,execute 方法中的线程会崩溃,而 submit 方法中的线程却可以复用?

本文已收录到我的面试小站 www.javacn.site,其中包含的内容有:Redis、JVM、并发、并发、MySQL、Spring、Spring MVC、Spring Boot、Spring Cloud、MyBatis、设计模式、消息队列等模块。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/796583.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

保持使用全局 HttpClient,但确保不同请求的 HttpRequestMessage 独立

保持使用全局 HttpClient,但确保不同请求的 HttpRequestMessage 独立这是推荐的最佳实践,因为 HttpClient 是设计为可重用的,你可以使用独立的 HttpRequestMessage 来确保每个请求有独立的请求头,而不影响其他请求。private static readonly HttpClient client = new HttpC…

清理C盘缓存,超简单的清理C盘缓存清理方法

清理C盘缓存是优化Windows系统性能的重要步骤,以下是一些超简单的清理C盘缓存的方法:使用磁盘清理工具 步骤: 右键点击C盘(系统盘),选择“属性”。 在C盘属性窗口中,点击“磁盘清理”按钮。 系统会分析C盘上的文件,并列出可以删除的文件类型。 勾选你想要删除的文件类型…

Pytorch安装(GPU_Windows,安装过CPU版的想再次安装GPU)

看过我之前那篇【Pytorch安装 CPU版本】的朋友应该知道,Pytorch安装步骤很复杂。但是其实弄清楚整个逻辑会简单很多,本篇为PytorchGPU安装。如果有朋友跟着我之前的帖子安装过的,想再安装一个GPU的,可以跟着我一起安装一下。我会把我遇到的坑以及经验都给大家分享一下。 Py…

STM32F103C8T6软件安装

本教程参考b站视频教程(STM32入门教程-2023版 细致讲解 中文字幕,第三集P3软件安装),将从一下几个方面进行安装: 1.安装Keil5 MDK软件 2.安装器件支持包 3.软件注册 4.安装ST-LINK驱动 5.安装USB转串口驱动 一、安装Keil5 MDK软件 找到软件的下载链接:https://jiangxieke…

基于pikachu靶场的水平越权详解

1. pikachu靶场搭建 如果你在之前已经使用过phpstudy了,参考pikachu 靶场环境搭建 如果没有,参考pikachu 靶场搭建 如果在靶场搭建中遇到一些问题,参考皮卡丘靶场搭建遇到的问题大全 2. 水平越权简介 水平越权是指攻击者通过获取与自己拥有相同权限级别的其他用户的访问权限…

如何实现两个机器时间同步-计算rtt+offset

背景: 之前的项目大致可以分为两层,逻辑层和设备层,运行在同一个主机上。最近在着手搭建一个仿真平台,在另外一台主机上部署机器人机器相关硬件设备,比如陀螺仪,轮机,雷达等。 由于两台主机的时间戳不同步问题,导致定位系统有问题,为此需要实现两个主机的时间同步。 具…

C# 操作xml(转)

四、xml 1、概念:XML可扩展的标记语言类似于HTML XML:存储数据 注意: XM工是严格区分大小写的。 XML标签也是成对出现的。 2、通过代码来创建xML文档 1、引用命名空间 using System.Xml; 2、创建XML文档对象 XmlDocument doc = new XmlDocument(); 3、创建第一行描述信息,并且…

代码随想录突击版刷题

704.二分查找 https://leetcode.cn/problems/binary-search/description/ 59.螺旋矩阵IIhttps://leetcode.cn/problems/spiral-matrix-ii/description/、 参考题解写出54.螺旋矩阵https://leetcode.cn/problems/spiral-matrix/description/class Solution { public:vector<i…

高精地图(HD map)的简单介绍

高精度语义地图的动态构建-HDMapNet - 知乎 (zhihu.com)