spring多线程事务回滚,java子线程异常抛出到主线程

  spring多线程事务回滚,java子线程异常抛出到主线程

  00-1010最近有个朋友问我这样一个问题。问题截图如下:

  这个问题比较笼统。我稍微详细描述一下:主线程向线程池提交一个任务。如果在这个任务执行过程中出现异常,主线程如何捕捉异常并回滚事务?

  00-1010先来看看基础。下图显示了这两个线程是如何运行的,

  左图是主线程启动一个子线程后,两个线程独立运行,互不干扰,生死有定数。从此你我就是路人!右图是主线程启动一个子线程后继续执行主线程的程序逻辑,子线程的执行结果是在某个节点阻塞得到的。

  对于上面提到的问题,主线程可以捕捉到子线程执行过程中发生的异常,这一定是解决问题的第二种方式。这里不得不提一个面试问题,来认识线程的可调用接口和可运行接口的区别:

  公共接口CallableV { V call()引发异常;}公共接口Runnable { public abstract void run();}可以看到call方法有返回值,run方法没有返回值。另外,call方法可以抛出异常,run方法不能。显然,为了捕获或知道子线程的运行结果,或者运行异常,我们都应该通过可调用接口来完成。

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

  公共类ExpSubThread实现Callable { @ Override public Object call()throws Exception { throw new NullPointerException();}}

一、提出问题

面对线程任务时,我们一般会提前设置一个线程池。线程池是预先计划的N个线程资源的集合。其优点是:

 

  执行任务时,不会创建新线程,而是使用线程池中现有的线程资源。任务执行的完成不是销毁线程,而是将线程资源返回线程池。从而在一定程度上节省了线程创建和销毁所消耗的资源,达到了线程资源重用的目的。因为线程池创建的大小是有上限的,所以线程池的另一个作用就是避免无限创建线程和无限占用应用资源导致系统崩溃的问题。常用的线程池有两种,一种是JDK自带的,一种是Spring线程池。后者常用于春季环境,两者类似。这里我们使用Spring API来构建一个线程池。

  public threadpooltaskmexecutor getThreadPool(){ threadpooltaskmexecutor=new threadpooltaskmexecutor();executor . setmaxpoolsize(100);//线程池中的最大线程数executor . setcorepoolsize(50);//线程池中核心线程的数量,executor . setqueuecapacity(50);//任务队列的大小,executor . setthreadname prefix( test _ );//线程前缀名executor . initialize();//线程初始化返回执行器;}

二、主线程与子线程

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

 

  @ Test void subthread exception Test(){ try {//创建新的subthread对象expsubthread=newexpsubthread();//构建线程池ThreadPooltask Executor Executor=getThreadPool();//提交子线程任务,提交方法FutureFuture=executor . submit(expusubthread);//在这里,可以操作主线程的其他业务流程。//阻塞,等待子线程对象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 事务的回滚内容请搜索盛行IT以前的文章或继续浏览下面的相关文章希望大家以后多多支持盛行IT!

郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。

留言与评论(共有 条评论)
   
验证码: