文章目录

  • 一、提出问题
  • 二、主线程与子线程
  • 三、线程池
  • 四、异常的捕获
  • 五、事务的回滚

一、提出问题

最近有一位朋友问了我这样一个问题,问题的截图如下:

这个问题问的相对比较笼统,我来稍微详细的描述下:主线程向线程池提交了一个任务,如果执行这个任务过程中发生了异常,如何让主线程捕获到该异常并且进行事务的回滚

二、主线程与子线程

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

  • 左侧的图,体现了主线程启动一个子线程之后,二者互不干扰独立运行,生死有命,从此你我是路人!
  • 右侧的图,体现了主线程启动一个子线程之后继续执行主线程程序逻辑,在某一节点通过阻塞的方式来获取子线程的执行结果。

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

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

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

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

public class ExpSubThread implements Callable {@Overridepublic 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;
}

四、异常的捕获

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

@Test
void 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基础】子线程任务发生异常,主线程事务如何回滚?相关推荐

  1. java 子线程退出_java – 在子线程完成执行之前主线程将退出吗?

    我读了2篇文章 在上面的文章中,在"线程终止"段中,它在Red中声明"如果父线程终止,它的所有子线程也会终止". 在上面的文章中,该页面的最后一行指出" ...

  2. Unity C# 子线程Action发送到主线程执行

    今天去面试..面试官竟然说子线程的Action不能发送到主线程执行... ...废话不说上干货 using System.Collections; using System.Collections.G ...

  3. 多线程遇到的问题:(2)子线程未运行完 主线程结束了

    问题: 用@Test测试多线程接口时,启动服务抛出异常: Singleton bean creation not allowed while singletons of this factory ar ...

  4. 为什么catch了异常,但事务还是回滚了?

    前几天我发了这篇文章<我来出个题:这个事务会不会回滚?>(https://blog.didispace.com/will-this-transcation-rollback/) 得到了很多 ...

  5. Android中Handler消息传递机制应用之子线程不允许操作主线程的组件

    场景 进程 一个Android应用就是一个一个进程,每个应用在各自的进程中运行. 线程 比进程更小的独立运行的基本单位,一个进程可以包含多个线程. 要求 一个TextView和一个Button,点击B ...

  6. UnityThread子线程使用只能在主线程中调用的函数或Unity API

    Unity的Socket网络编程中,为了防止程序卡死,一般使用多线程来监听端口,当收到来自客户端的消息时,需要显示在界面上.但是如果直接在子线程中操作Unity的界面或物体会报错.国外一个大神写了一个 ...

  7. Qt与OpenCV编程:在子线程打开摄像头用主线程显示

    前言 1.在做图像处理开发中,比例做目标跟踪识别的时候,用OpenCV一直在处理摄像头传入的数据,有时候会出现界面卡死或者未响应的状态,这是因为事件循环一直等待处理函数的返回而导致阻塞事件循环,这样一 ...

  8. python 主程序等待 子线程_Python多线程中主线程等待所有子线程结束的方法

    Python多线程中主线程等待所有子线程结束的方法 发布时间:2020-07-30 14:39:04 来源:亿速云 阅读:77 作者:小猪 这篇文章主要讲解了Python多线程中主线程等待所有子线程结 ...

  9. java等待5秒_Java并发编程-主线程等待子线程解决方案

    主线程等待所有子线程执行完成之后,再继续往下执行的解决方案 public class TestThread extends Thread { public void run() { System.ou ...

最新文章

  1. 实现网页中按钮刷新的N种方法
  2. 怎样定义网页里的关键字关键词
  3. VTK:网格之Subdivision
  4. nz-input-group is not a known element的解决方法
  5. IIS——MIME介绍与添加MIME类型
  6. Vue:vue中axios发起http请求报错net::ERR_CERT_DATE_INVALID
  7. springboot 指定 logback_Spring Boot日志框架实战解析
  8. 网站性能测试工具 webbench 的安装和使用-linux
  9. ubuntu安装ROBOWARE
  10. android 识别车牌颜色,Android、ios移动端车牌识别sdk / 车牌识别API
  11. 手把手教你实现——Python文字(汉字)转语音教程,举一反三~
  12. Excel基础(08)IF函数
  13. Box2D翻译_第二章
  14. html增加语音朗读功能,给wordpress主题添加上语音播放文章内容文本朗读功能
  15. jsch中ChannelShell与ChannelExec区别
  16. 瑞云专访CG新生力量:《星野》C4D动画毕设制作分享
  17. 商业php源码,Thinkphp内核2019全新UI威客任务平台网站商业原版源码
  18. JS模仿腾讯微博app撕纸效果
  19. VMware vSphere 虚拟化平台的安装及使用
  20. 支付宝技术专家李战斌:安防视频行为分析系统的技术演进及应用场景 | 2018FMI人工智能与大数据高峰论坛(深圳站)

热门文章

  1. 量化交易,关于止损止盈的一点思考
  2. 【汇正财经】12.23日盘面回顾和行情解析
  3. svg-icon图片修改颜色的两种方法
  4. 成绩录入时的及格与不及格人数统计的个人解法
  5. 【基于Java的移动OA系统】
  6. Web控制SG90 9g舵机(180度版)-MicroPython-NodeMcu-Esp8266开发板
  7. 怎么给pdf文件添加水印
  8. heic图片转换jpg教程
  9. 分巧克力 c/c++
  10. 神经网络控制法的工作原理,什么是神经网络控制