子线程如何等待主线程执行完再执行

简介: 在业务不断迭代中,复杂逻辑难免出现。例如在大业务方法中需临时执行不影响主流程的特殊逻辑,可用子线程处理。若子线程依赖主线程结果(如数据库事务),需确保主线程先完成。文章提出两种解决方式:一是利用Spring事务传播机制拆分方法;二是通过判断父线程状态实现延迟执行,提供`ThreadEndExec`工具类,保守等待15秒后执行子线程任务,保证逻辑顺序与数据一致性。

  工作中由于需求不断迭代,导致业务变得越来越复杂,一些奇怪却又合理的代码逻辑就出现了。

比如我们需要在一个巨大的业务逻辑方法中需要临时执行一些特殊的业务逻辑,但是这部分逻辑对主线程的执行结果不影响,那么我们就需要开一个子线程执行。假设子线程执行的部分业务是需要依赖主线程执行的结果(数据库的数据)的话,就必须要保证执行子线程的时候,主线程已经执行完毕(提交了事务)。

那么如果保证呢,我具体想了两种方式

第一种:通过spring的事务传播机制来实现,比如把主方法拆分成两个方法。第一个方法用来实现业务的主要逻辑,第二个方法用来处理特殊的操作,第一个方法上我们单独开一个事务(propagation = Propagation.REQUIRES_NEW),再执行第二个方法时第一个方法事务已经提交,这样就很好的解决了这一问题。

第二种:考虑到复杂系统的代码维护难度,对代码改动过大的话可能会产生不可预测的严重后果,老板可能就不介意对现有的方法做拆分,在这种情况下如何保证主方法已执行完呢。下面是我写的一个折中的方案,基本上能满足需求。

csharp

代码解读

复制代码

public interface EndExec <T>{

    void exec(T  t);
}

csharp

代码解读

复制代码

public interface EndExecList<T> {

    void exec(List<T> list);
}

scss

代码解读

复制代码

/**
 * 线程执行于父线程结束后 工具
 */
public class ThreadEndExec {

    public static<T> void exec(EndExec<T> exec, T  t){
        Thread thread = Thread.currentThread();
        CommonUtils.getThreadPoolExecutor().execute(()->{
            int second = 0;
            while(!Arrays.asList(Thread.State.WAITING,Thread.State.TERMINATED).contains(thread.getState())
                && second < 15){
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                second = second + 1;
            }
            exec.exec(t);
        });
    }

    public static<T> void execList(EndExecList<T> exec,List<T> list){
        Thread thread = Thread.currentThread();
        CommonUtils.getThreadPoolExecutor().execute(()->{
            int second = 0;
            while(!Arrays.asList(Thread.State.WAITING,Thread.State.TERMINATED).contains(thread.getState())
                   && second < 15){
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                second = second + 1;
            }
            exec.exec(list);
        });
    }

}

bash

代码解读

复制代码

ThreadEndExec.exec((u)->{
            ...
},user);

上面是通过获取父线程的线程状态来判断父线程是否已经执行完成,然后再保守等待15秒的时间


转载来源:https://juejin.cn/post/7297024168604106788

相关文章
|
8月前
|
人工智能 监控 安全
Go通道机制与应用详解
本文全面解析了Go语言中的通道(Channel),从基础概念到高级应用,涵盖创建、操作、垃圾回收及实际场景使用。通道作为Go并发模型的核心,支持协程间安全高效的数据通信与同步。文章介绍了无缓冲和有缓冲通道的特性,以及发送、接收、关闭等操作,并探讨了`select`语句、超时处理、遍历通道等高级用法。此外,还深入分析了通道的垃圾回收机制,包括引用计数、生命周期管理和循环引用问题。最后通过数据流处理、任务调度和状态监控等实例,展示了通道在实际开发中的广泛应用。理解通道不仅有助于构建高并发系统,还能优化资源管理,提升程序性能。
263 31
|
6月前
|
存储 缓存 人工智能
Java int和Integer的区别
本文介绍了Java中int与Integer的区别及==与equals的比较机制。Integer是int的包装类,支持null值。使用==比较时,int直接比较数值,而Integer比较对象地址;在-128至127范围内的Integer值可缓存,超出该范围或使用new创建时则返回不同对象。equals方法则始终比较实际数值。
205 0
|
9月前
|
测试技术 Python
Python 的 for-else 循环结构是如何工作的?
本文介绍了Python中不太为人熟知但实用的`for-else`循环结构。通过示例讲解了其工作原理:当`for`循环正常结束而未遇到`break`时,执行`else`块。文章提供了两个应用场景——检查素数和列表搜索,帮助理解如何高效使用该结构。最后提醒,若无需条件跳出循环,普通`for`循环已足够。
412 33
|
7月前
|
SQL 缓存 关系型数据库
MySQL 慢查询是怎样优化的
本文深入解析了MySQL查询速度变慢的原因及优化策略,涵盖查询缓存、执行流程、SQL优化、执行计划分析(如EXPLAIN)、查询状态查看等内容,帮助开发者快速定位并解决慢查询问题。
287 0
|
7月前
|
算法 安全 Go
如何通过 go 语言实现雪花算法?
在Go语言中,可通过实现雪花算法(Snowflake)生成分布式唯一ID。该算法由Twitter提出,将64位ID分为时间戳、机器ID和序列号三部分。文章介绍了算法结构、Go语言实现代码、代码说明、示例输出、优点及注意事项。此算法具备高性能、分布式支持和有序性特点,适用于数据库主键等场景。使用时需确保机器ID唯一与时钟同步。
184 0
|
负载均衡 监控 Java
SpringCloud常见面试题(一):SpringCloud 5大组件,服务注册和发现,nacos与eureka区别,服务雪崩、服务熔断、服务降级,微服务监控
SpringCloud常见面试题(一):SpringCloud 5大组件,服务注册和发现,nacos与eureka区别,服务雪崩、服务熔断、服务降级,微服务监控
27450 8
SpringCloud常见面试题(一):SpringCloud 5大组件,服务注册和发现,nacos与eureka区别,服务雪崩、服务熔断、服务降级,微服务监控
|
6月前
|
人工智能 Java 开发者
spring-boot重试机制:Guava-Retrying
在业务开发中,请求第三方接口时常因网络问题导致失败,此时可使用重试机制解决。本文介绍基于Guava实现的guava-retrying,通过封装HTTP请求工具类并结合重试策略,提升接口调用稳定性。内容涵盖工具类编写、重试配置及监听处理,适用于Java开发者优化系统健壮性。
202 1
|
6月前
|
人工智能 负载均衡 监控
使用 Go 和 Gin 实现高可用负载均衡代理服务器
本文基于Go语言和Gin框架,实现了一个企业级负载均衡代理服务器,支持动态路由、健康检查、会话保持等功能。具备高可用性与高性能,单节点支持100k+ QPS,延迟达亚毫秒级,并提供完整的压力测试方案与优化建议。
200 7
|
6月前
|
人工智能 JSON Shell
go mod依赖管理
本文介绍了Go语言中如何管理并使用自己的包以及导入第三方包的方法。内容涵盖包的目录结构、go.mod文件的初始化、import的正确使用方式、init函数的作用及执行顺序,以及如何下载和管理第三方库。通过具体示例演示了包的导入、别名设置、函数调用和运行方式,帮助开发者更好地理解和掌握Go模块化编程的核心技巧。
266 5
|
6月前
|
SQL 人工智能 关系型数据库
如何使用MySQL的事件调度器?
MySQL事件调度器允许在指定时间或间隔自动执行SQL语句,可用于数据清理、报告生成等任务。本文介绍其配置、创建、修改、删除事件的方法,并提供Java操作示例代码,帮助实现数据库定时任务管理。
247 0