Java捕获ThreadPoolExecutor内部线程异常的四种方法

2025-03-14 01:50

本文主要是介绍Java捕获ThreadPoolExecutor内部线程异常的四种方法,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

《Java捕获ThreadPoolExecutor内部线程异常的四种方法》这篇文章主要为大家详细介绍了Java捕获ThreadPoolExecutor内部线程异常的四种方法,文中的示例代码讲解详细,感...

方案 1

使用 execute + try-catch 记录异常

import Java.util.concurrent.*;
 
public class ThreadPoolExceptionDemo {
    public static vwww.chinasem.cnoid main(String[] args) {
        ThreadPoolExecutor executor = new ThreadPoolExecutor(
                2, 4, 10, TimeUnit.SECONDS,
                new LinkedblockingQueue<>(),
                new ThreadFactory() {
                    private int count = 1;
                    @Override
                    public Thread newThread(Runnable r) {
                        return new Thread(r, "custom-thread-" + count++);
                    }
                });
 
        executor.execute(() -> {
            try {
                System.out.println(Thread.currentThread().getName() + " 正在执行任务");
                throw new RuntimeException("任务异常");
            } catch (Exception e) {
                System.err.println("线程 " + Thread.currentThread().getName() + " 捕获异常: " + e.getMessage());
                e.printStackTrace();
            }
        });
 
        executor.shutdown();
    }
}

方案 2

使用 submit + Future

submit() 方法返回 Future,可以通过 get() 方法捕获异常:

public static void main(String[] args) {
    ExecutorService executor = Executors.newFixedThreadPool(2);
 
    Future<?> future = executor.submiwww.chinasem.cnt(() -> {
        System.out.println(Thread.currentThread().getName() + " 正在执行任务");
        throw new RuntimeException("任务异常");
    });
 
    try {
        future.get(); // get() 会抛出 ExecutionException
    } catch (InterruptedException | ExecutionException e) {
        System.err.println("线程 " + Thread.currentThread().getName() + " 捕获异常: " + e.getCause().getMessage());
        e.printStackTrace();
    }
 
    executor.shutdown();
}

注意

  • get() 方法会阻塞主线程直到任务完成。
  • ExecutionException 的 getCause() 方法可以获取原始异常。

方案 3

自定义 UncaughtExceptionHandler

可以为线程设置 UncaughtExceptionHandler,当 Runnable 没有捕获异常时,ThreadPoolExecutor 也不会吞掉异常:

public class ThreadPoolWithExceptionHandler {
    public static void main(String[] args) {
        ThreadFactory threadFactory = r -> {
            Thread t = new Thread(r);
            t.setUncaughtExceptionHandler((thread, throwable) -> {
                System.err.println("线程 " + thread.getName() + " 发生异常: " + throwable.getMessage());
                throwable.printStackTrace();
            });
            returnChina编程 t;
        };
 
        ExecutorService executor = new ThreadPoolExecutor(
                2, 4, 10, TimeUnit.SECONDS,
                new LinkedBlockingQueue<>(),
                threadFactory
        );
 
        executor.execute(() -> {
            System.out.println(Thread.currentThread().getName() + " 正在执行任务");
            throw new RuntimeException("任务异常");
        });
 
        executor.shutdown();
    }
}

方案 4

重写 afterExecute 方法

如果你要在 ThreadPoolExecutor 内部直接处理异常,可以继承 ThreadPoolExecutor 并重写 afterExecute()

class CustomThreadPoolExecutor extends ThreadPoolExecutor {
    public CustomThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue) {
        super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue);
    }
 
    @Override
    protected void afterExecute(Runnable r, Throwable t) {
        super.afterExecute(r, t);
        if (t == null && r instanceof Future<?>) {
            try {
                ((Future<?>) r).get(); // 获取任务结果,捕获异常
            } catch (InterruptedException | ExecutionException e) {
                t = e.getCause();
            }
        }
        if (t != null) {
            System.err.println("线程 " + Thread.currentThread().getName() + " 发生异常: " + t.getMessage());
            t.printStackTrace();
        }
    }
}
 
public class ThreadPoolAfterExecuteDemo {
    public static void main(String[] args) {
        ThreadPoolExecutor executor = new CustomThreadPoolExecutor(2, 4, 10, TimeUnit.SECOChina编程NDS, new LinkedBlockingQueue<>());
 
        executor.submit(() -> {
            System.out.println(Thread.currentThread().getName() + " 正在执行任务");
            throw new RuntimeException("任务异常");
        });
 
        executor.shutdown();
    }
}

结论

方案适用场景缺点
try-catch 手动处理适用于 execute()代码侵入性强,所有任务都要加 try-catch
Future.get() 捕获异常适用于 submit()get() 会阻塞主线程
UncaughtExceptionHandler适用于 exe编程China编程cute()不能捕获 submit() 提交的异常
afterExecute() 适用于 execute() 和 submit()需要继承 ThreadPoolExecutor

推荐:

  • 任务内部 try-catch 适用于 execute()
  • Future.get() 适用于 submit()
  • 统一异常处理建议使用 afterExecute() 或 UncaughtExceptionHandler

到此这篇关于Java捕获ThreadPoolExecutor内部线程异常的四种方法的文章就介绍到这了,更多相关Java ThreadPoolExecutor异常内容请搜索China编程(www.chinasem.cn)以前的文章或继续浏览下面的相关文章希望大家以后多多支持China编程(www.chinasem.cn)!

这篇关于Java捕获ThreadPoolExecutor内部线程异常的四种方法的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1153735

相关文章

SpringBoot接收JSON类型的参数方式

《SpringBoot接收JSON类型的参数方式》:本文主要介绍SpringBoot接收JSON类型的参数方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一、jsON二、代码准备三、Apifox操作总结一、JSON在学习前端技术时,我们有讲到过JSON,而在

Spring-AOP-ProceedingJoinPoint的使用详解

《Spring-AOP-ProceedingJoinPoint的使用详解》:本文主要介绍Spring-AOP-ProceedingJoinPoint的使用方式,具有很好的参考价值,希望对大家有所帮... 目录ProceedingJoinPoijsnt简介获取环绕通知方法的相关信息1.proceed()2.g

Python中Windows和macOS文件路径格式不一致的解决方法

《Python中Windows和macOS文件路径格式不一致的解决方法》在Python中,Windows和macOS的文件路径字符串格式不一致主要体现在路径分隔符上,这种差异可能导致跨平台代码在处理文... 目录方法 1:使用 os.path 模块方法 2:使用 pathlib 模块(推荐)方法 3:统一使

Spring Security注解方式权限控制过程

《SpringSecurity注解方式权限控制过程》:本文主要介绍SpringSecurity注解方式权限控制过程,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一、摘要二、实现步骤2.1 在配置类中添加权限注解的支持2.2 创建Controller类2.3 Us

Spring MVC跨域问题及解决

《SpringMVC跨域问题及解决》:本文主要介绍SpringMVC跨域问题及解决方案,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录跨域问题不同的域同源策略解决方法1.CORS2.jsONP3.局部解决方案4.全局解决方法总结跨域问题不同的域协议、域名、端口

SpringBoot项目启动错误:找不到或无法加载主类的几种解决方法

《SpringBoot项目启动错误:找不到或无法加载主类的几种解决方法》本文主要介绍了SpringBoot项目启动错误:找不到或无法加载主类的几种解决方法,具有一定的参考价值,感兴趣的可以了解一下... 目录方法1:更改IDE配置方法2:在Eclipse中清理项目方法3:使用Maven命令行在开发Sprin

JAVA SE包装类和泛型详细介绍及说明方法

《JAVASE包装类和泛型详细介绍及说明方法》:本文主要介绍JAVASE包装类和泛型的相关资料,包括基本数据类型与包装类的对应关系,以及装箱和拆箱的概念,并重点讲解了自动装箱和自动拆箱的机制,文... 目录1. 包装类1.1 基本数据类型和对应的包装类1.2 装箱和拆箱1.3 自动装箱和自动拆箱2. 泛型2

SpringBoot操作MaxComputer方式(保姆级教程)

《SpringBoot操作MaxComputer方式(保姆级教程)》:本文主要介绍SpringBoot操作MaxComputer方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的... 目录引言uqNqjoe一、引入依赖二、配置文件 application.properties(信息用自己

C# 委托中 Invoke/BeginInvoke/EndInvoke和DynamicInvoke 方法的区别和联系

《C#委托中Invoke/BeginInvoke/EndInvoke和DynamicInvoke方法的区别和联系》在C#中,委托(Delegate)提供了多种调用方式,包括Invoke、Begi... 目录前言一、 Invoke方法1. 定义2. 特点3. 示例代码二、 BeginInvoke 和 EndI

JavaScript中的Map用法完全指南

《JavaScript中的Map用法完全指南》:本文主要介绍JavaScript中Map用法的相关资料,通过实例讲解了Map的创建、常用方法和迭代方式,还探讨了Map与对象的区别,并通过一个例子展... 目录引言1. 创建 Map2. Map 和对象的对比3. Map 的常用方法3.1 set(key, v