首页 > 其他分享 >面试官:线程池遇到未处理的异常会崩溃吗?

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

时间:2024-09-13 15:26:04浏览次数:10  
标签:面试官 execute submit System 线程 println 崩溃 public

首先,这个问题考察的是你对线程池 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() {
            @Override
            public 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、设计模式、消息队列等模块。

标签:面试官,execute,submit,System,线程,println,崩溃,public
From: https://www.cnblogs.com/vipstone/p/18412245

相关文章

  • 多线程篇(线程池 - 整体介绍)(持续更新迭代)
    目录一、线程池(并发编程的艺术)1.Java中的线程池1.1.线程池的实现原理1.2线程池的使用1.线程池的创建2.向线程池提交任务3.关闭线程池4.合理地配置线程池5.线程池的监控1.3本章小结2.Executor框架2.1Executor框架简介1.Executor框架的两级调度模型2.......
  • 一个Android App最少有几个线程?实现多线程的方式有哪些?
    本文首发于公众号“AntDream”,欢迎微信搜索“AntDream”或扫描文章底部二维码关注,和我一起每天进步一点点多线程编程是Android应用开发中非常重要的一个环节,可以有效地提升应用的性能和用户体验。下面是对Android中多线程相关内容的详细介绍,包括app最少有几个线程。1.基本概念主线......
  • Java线程状态及生命周期
    基础概念Java线程在运行生命周期中的指定时刻只可能处于这6种不同状态的其中一个状态,分别是:NEW:初始状态,这是线程被创建出来但没有被调用start()。RUNNABLE:运行状态,线程被调用了start()等待运行的状态。BLOCKED:阻塞状态,等待WAITING:等待状态,表示该线程需要等待其他线程做出......
  • 线程池的应用-->2
    1.自定义线程工程当需要自定义线程的名字,线程的优先级,精灵线程状态时,需要自定义线程工厂。如何自定义线程工厂自定义工厂类,实现ThreadFactory接口,重写方法newThread()在创建线程池对象时,传递上述线程工厂对象publicclassTest5{publicstaticvoidmain(Strin......
  • 线程池介绍、参数、执行过程
    线程池管理一系列线程的资源池,提供了一种限制和管理线程资源的方式线程池一般用于执行多个不相关联的耗时任务,没有多线程的情况下,任务顺序执行,使用了线程池的话可让多个不相关联的任务同时执行好处降低资源消耗:频繁的线程创建和销毁会消耗系统资源,线程池可以复用已经创建......
  • day11-多线程
    一、线程安全问题线程安全问题出现的原因?存在多个线程在同时执行同时访问一个共享资源存在修改该共享资源线程安全:多个线程同时修改同一个资源取钱案例小明和小红是一对夫妻,他们有一个共同的账户,余额是10万元如果小明和小红同时来取钱,并且2人各自......
  • 机器线程数量突然激增的原因是什么?
    机器上的线程数量突然激增可能由多种原因引起。以下是一些常见的原因及其可能的解决方法:1.应用程序或进程问题某个应用程序或进程可能创建了大量线程,这通常是由于编程错误、资源泄漏或不当的线程管理引起的。解决方法:使用系统监控工具(如任务管理器、top、htop)查看哪个......
  • UNO 已知问题 在后台线程触发 SKXamlCanvas 的 Invalidate 且在 PaintSurface 事件抛
    本文记录一个UNO已知问题,在UNO里面可以利用SKXamlCanvas对接Skia绘制到应用里面。如果此时在后台线程里面调用SKXamlCanvas的Invalidate触发界面的重新刷新,但在具体的执行绘制PaintSurface事件里面对外抛出异常,将会导致应用炸掉背景:我准备在UNO里面将Microsoft......
  • 面试产品经理,怎样描述过往经历,才能让面试官印象深刻?
    金三银四求职季,你是不是也有面试的冲动!但面试并不是头脑一热就能取得好结果,在此之前,必须得有周全的准备,才能应对好面试官的“连环问”!所以,给大家分享这篇产品经理面试干货文章,别忘记双击哦!今天文章的主要解答:产品经理面试有哪些基本流程和常见误区?以及我们该如何好自我介绍!......
  • 《黑神话:悟空》游戏启动时闪退弹窗“找不到msvcp100.dll”文件该怎么办?黑神话悟空游戏
    在启动《黑神话:悟空》时,若遇到闪退弹窗并提示“找不到msvcp100.dll”文件,别紧张。这可能是文件缺失造成的。您可以使用系统的修复工具尝试解决,或者从可靠来源获取该文件进行安装,有望解决此问题。本篇将为大家带来《黑神话:悟空》游戏启动时闪退弹窗“找不到msvcp100.dll”文件该......