使用CountDownLatch解决实际业务问题的思考过程

使用CountDownLatch解决实际业务问题过程

使用的技术比较简单,主要记录下思考和解决的过程

业务背景:

1、高管在页面对审批申请单进行审批(调用submit()方法)

2、新的产品需求,要在审批提交时,同步执行另外的一系列操作(已有现成的doExecute()方法,直接调用即可)

3、数据库为MySQL(事务的隔离级别为默认,可重复读),代码中事务由spring事务管理器管理

开发过程:

直接在submit()方法中新起一个线程调用doExecute()方法

出现问题:

测试过程中发现部分数据状态未正常更新,排查代码逻辑未发现问题,后发现submit()方法更新了A表,doExecute()方法也更新了A表,这两个方法是在不同的线程中执行的,属于不同的事务,后提交的事务会覆盖前一事务提交的信息。

解决方法

1、改成同步调用doExecute()方法。之后发现,doExecute()方法逻辑非常复杂,执行时间较长,需要5.5秒中,原submit()方法执行时间约2.4秒,一共需要用户等待8秒,严重影响了用户体验,而且此用户一般为高管。

2、优化doExecute()业务逻辑代码。经过痛苦的业务逻辑梳理,代码优化后,执行时间减少了1.4秒,杯水车薪。

3、既然两个方法本就不需要同步执行,那我等submit方法执行完成之后,也就是事务提交之后再调用doExecute()方法即可。

ps:因为submi()方法使用的模板方法设计模式,而且只是在满足部分条件后才调用doExecute()方法,所以不能直接在submit()方法后直接调用doExecute()方法

4、让线程先后执行的方式有,Thread.join(),CyclicBarrier,CountDownLatch。一开始考虑到复用,使用CyclicBarrier,但是在多线程环境中,完全不能保证AB线程的先后顺序,然后使用join()方法,但是又发现SpringMVC的controller层接收请求的线程使用的是线程池,在doExecute()方法中调用thread.join()后,doExecute()方法一直被阻塞。最后通过CountDownLatch + ThreadLocal 解决了线程submit()执行完成,事务提交后,再执行doExecute()方法。

使用CountDownLatch解决实际业务问题的思考过程_第1张图片                    

                    

你可能感兴趣的:(Idea)