千家信息网

Java子线程任务异常和主线程事务回滚问题怎么解决

发表于:2026-11-01 作者:千家信息网编辑
千家信息网最后更新 2026年11月01日,这篇文章主要介绍了Java子线程任务异常和主线程事务回滚问题怎么解决的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇Java子线程任务异常和主线程事务回滚问题怎么解决文章都
千家信息网最后更新 2026年11月01日Java子线程任务异常和主线程事务回滚问题怎么解决

这篇文章主要介绍了Java子线程任务异常和主线程事务回滚问题怎么解决的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇Java子线程任务异常和主线程事务回滚问题怎么解决文章都会有所收获,下面我们一起来看看吧。

一、提出问题

主线程向线程池提交了一个任务,如果执行这个任务过程中发生了异常,如何让主线程捕获到该异常并且进行事务的回滚。

二、主线程与子线程

先来看看基础,下图体现了两种线程的运行方式,

  • 左侧的图,体现了主线程启动一个子线程之后,二者互不干扰独立运行,生死有命,从此你我是路人!

  • 右侧的图,体现了主线程启动一个子线程之后继续执行主线程程序逻辑,在某一节点通过阻塞的方式来获取子线程的执行结果。

对于上文中提出的问题,一定是第二种才能解决主线程能够捕获子线程执行过程中发生的异常。这里就不得不提一个面试题,实现线程的两个接口Callable与Runnable之间的区别:

public interface Callable {    V call() throws Exception;}
public interface Runnable {    public abstract void run();}

可以看到call方法带返回值,run方法没有返回值。另外call方法可以抛出异常,run方法不可以。很明显,我们为了要捕获或得知子线程的运行结果,或者运行异常,都应该通过Callable接口来实现。

这里我们写一个ExpSubThread类(子线程异常模拟类),实现Callable接口,不做过多的动作,直接抛出一个空指针异常。

public class ExpSubThread implements Callable {    @Override    public Object call() throws Exception {        throw new NullPointerException();    }}

三、线程池

在面临线程任务时,通常我们会预先建立一个线程池,线程池是预先规划好的n个线程资源的集合。它的好处在于:

  • 执行任务时,不是新建一个线程,而是使用线程池内已有的线程资源。任务执行完成也不是销毁线程,而是将线程资源归还线程池。所以在一定程度上,节省了线程创建和销毁所消耗的资源,达到线程资源重复利用的目的。

  • 因为线程池创建的大小是有上限的,所以线程池还有另外的一个作用就是避免线程无限制的被创建,避免应用资源无限制的被占用导致的系统宕掉的问题。

常用的线程池有两种,一种是JDK自带的,一种是Spring线程池,在Spring环境下后者常常被使用,二者大同小异。这里我们使用Spring API来构建一个线程池。

public ThreadPoolTaskExecutor getThreadPool(){        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();        executor.setMaxPoolSize(100);  //线程池最大线程数        executor.setCorePoolSize(50);//线程池核心线程数        executor.setQueueCapacity(50);//任务队列的大小        executor.setThreadNamePrefix("test_"); //线程前缀名        executor.initialize(); //线程初始化        return executor;}

四、异常的捕获

下面是我写的一个测试用例,在这里它代表了主线程的程序执行流程

@Testvoid subThreadExceptionTest() {        try{            //新建子线程对象            ExpSubThread expSubThread = new ExpSubThread();            //构建线程池            ThreadPoolTaskExecutor executor = getThreadPool();            //提交子线程任务,submit方法            Future future = executor.submit(expSubThread);            //在这里可以做主线程的业务其他流程操作            //阻塞等待子线程的执行结果            Object obj = future.get();          }catch (Exception e){            e.printStackTrace();            //事务回滚        }}

这里需要注意的是使用submit方法提交子线程任务到线程池内执行。ThreadPoolTaskExecutor有两种执行线程任务的方法,一种是execute方法,一种是submit方法。

  • execute方法没有返回值,所以无法判断任务是否成功完成,对应的线程类实现Runnable接口。

  • submit方法有返回值,返回一个Future,对应的线程类实现Callable接口。

Future.get()方法达到了阻塞主线程的目的,从而可以判断子线程任务的执行结果,并且get方法可以抛出异常。

    V get() throws InterruptedException, ExecutionException;

下面这张图是上面的测试用例程序程序e.printStackTrace();的效果,从图中可以看到两个Exception异常,一个是我们在子线程任务中以模拟的方式主动抛出的空指针异常,另一个由于空指针引发的get方法抛出的ExecutionException。

五、事务的回滚

上文中大家已经看到我们通过

  • 线程类实现Callable接口,达到了获取线程返回值,或者异常抛出的目的。

  • submit可以提交线程任务到线程池,并且可以获得子线程执行结果的返回值Future。

  • Future的get()方法可以获取子线程执行信息,包括异常的抛出。

那么既然我们已经可以在主线程内感知或catch子线程的异常信息了,下一步主线程的事务回滚是不是就太简单了?

  • jdbc 就conn.rollback()实现事务的回滚

  • spring环境下使用@Transactional注解就可以了。

关于"Java子线程任务异常和主线程事务回滚问题怎么解决"这篇文章的内容就介绍到这里,感谢各位的阅读!相信大家对"Java子线程任务异常和主线程事务回滚问题怎么解决"知识都有一定的了解,大家如果还想学习更多知识,欢迎关注行业资讯频道。

线程 任务 方法 事务 问题 接口 资源 结果 程序 运行 指针 方式 目的 知识 阻塞 上文 两个 个子 交子 信息 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 疫情对互联网科技公司影响 互联网巨头反垄断金融科技 互联网金融 科技 世界互联网领先科技成果 北京互联网络科技有限公司 融势互联网科技 互联网 视角下的科技创新 融贸通互联网科技 互联网企业和科技型企业 栖莱科技互联网股份有限公司 岳阳华臻互联网科技有限公司 互联网科技大奖都有哪些公司 长沙茂晟互联网科技有限公司 国大互联网教育科技有限公司薪资 山东子淼互联网科技有限公司 小米互联网科技园入驻 互联网科技融合创新 美国五大互联网科技公司市值多少 互联网科技大佬云集 黑龙江互联网科技公司 互联网科技公司起名 A股互联网金融科技公司 金融科技 互联网金融 美国互联网科技 互联网金融科技公司干啥的 福建科技产业互联网发展 允成互联网科技有限公司融资 华中科技大学互联网的牛人 科技互联网经济论坛 美国五大互联网科技公司市值多少
0