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

 更新时间:2025年03月13日 15:22:42   作者:大大怪~将军  
这篇文章主要为大家详细介绍了Java捕获ThreadPoolExecutor内部线程异常的四种方法,文中的示例代码讲解详细,感兴趣的小伙伴可以参考一下

方案 1

使用 execute + try-catch 记录异常

import java.util.concurrent.*;
 
public class ThreadPoolExceptionDemo {
    public static void 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.submit(() -> {
        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();
            });
            return 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.SECONDS, 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适用于 execute()不能捕获 submit() 提交的异常
afterExecute() 适用于 execute() 和 submit()需要继承 ThreadPoolExecutor

推荐:

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

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

相关文章

  • Java使用openssl检测网站是否支持ocsp

    Java使用openssl检测网站是否支持ocsp

    OCSP在线证书状态协议是为了替换CRL而提出来的。对于现代web服务器来说一般都是支持OCSP的,OCSP也是现代web服务器的标配,这篇文章主要介绍了Java使用openssl检测网站是否支持ocsp,需要的朋友可以参考下
    2022-07-07
  • java实现多文件上传至本地服务器功能

    java实现多文件上传至本地服务器功能

    这篇文章主要为大家详细介绍了java实现多文件上传至本地服务器功能,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2018-01-01
  • java executor包参数处理功能 

    java executor包参数处理功能 

    这篇文章主要介绍了java executor包参数处理功能,sql语句中的参数赋值是有由executor包中的parameter子包完成的。parameter子包其实只有一个parameterHandler接口并且它定义了两个方法,下面我们就来看详细内容吧,需要的朋友可以参考一下
    2022-02-02
  • 解决SpringBoot自定义拦截器和跨域配置冲突的问题

    解决SpringBoot自定义拦截器和跨域配置冲突的问题

    这篇文章主要介绍了解决SpringBoot自定义拦截器和跨域配置冲突的问题,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-08-08
  • @SpringBootTest 注解报红问题及解决

    @SpringBootTest 注解报红问题及解决

    这篇文章主要介绍了@SpringBootTest 注解报红问题及解决,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-11-11
  • SpringMVC异常处理器编写及配置

    SpringMVC异常处理器编写及配置

    这篇文章主要介绍了SpringMVC异常处理器编写及配置,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-08-08
  • Spring Java-based容器配置详解

    Spring Java-based容器配置详解

    这篇文章主要介绍了Spring Java-based容器配置详解,涉及注解和@Configuration类以及@Beans的相关知识,具有一定参考价值,需要的朋友可以了解。
    2017-10-10
  • macOS上使用gperftools定位Java内存泄漏问题及解决方案

    macOS上使用gperftools定位Java内存泄漏问题及解决方案

    这篇文章主要介绍了macOS上使用gperftools定位Java内存泄漏问题,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2020-07-07
  • springboot+redis缓存的实现方案

    springboot+redis缓存的实现方案

    本文介绍了Spring Boot与Redis结合实现缓存的三种方案:注解方式、注解切面类方式和使用样例,通过这些方案,可以有效地提高应用程序的性能和响应速度
    2025-03-03
  • spring boot集成redisson的最佳实践示例

    spring boot集成redisson的最佳实践示例

    这篇文章主要为大家介绍了spring boot集成redisson的最佳实践示例,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-03-03

最新评论