让调用者自己干活的特殊线程池

让调用者自己干活的特殊线程池

1. 相关背景

单元测试时, 我们的某些业务代码可能是在线程池中运行的,可能会出现各种不一致的情况。

这时候可以hack一下, 创建一个调用者直接执行的线程池,避免干扰;

Spring-core之中也有一个对应的同步线程池, 简单任务也可以使用,根据需要确定使用哪个即可:

org.springframework.core.task.SyncTaskExecutor implements TaskExecutor { }

2. 实现代码



import java.util.concurrent.*;

// 让调用者自己执行的线程池
public class CallerRunsExecutor extends ThreadPoolExecutor {
    public CallerRunsExecutor() {
        super(0, 1, 0, TimeUnit.MILLISECONDS, new ArrayBlockingQueue<Runnable>(1));
    }

    @Override
    public void execute(Runnable command) {
        command.run();
    }

    // 获取实例
    public static CallerRunsExecutor getInstance() {
        return new CallerRunsExecutor();
    }
}

3. SpringBoot配置实例

在 SpringBoot 对应的 @Configuration 配置中对Bean进行hack:


    // 是否是集成测试环境
    public static final AtomicBoolean itEnv = new AtomicBoolean(false);

    @Bean
    public ExecutorService longtimeExecutor() {
        if (itEnv.get()){
            // 是否是集成测试环境
            return CallerRunsExecutor.getInstance();
        }
        return new ThreadPoolExecutor(1, 10,
                60L,
                TimeUnit.SECONDS,
                new LinkedBlockingQueue<>(2),
                new CustomizableThreadFactory("xxxExecutor-"));
    }

然后在基础的单元测试代码中对相应的值进行设置:


    @BeforeClass
    public static void initEnv() {
        // ...
        // 是否是集成测试环境
        XXXXConfiguration.itEnv.set(true);

    }

如果需要的话,也可以配合 @ConditionalOnMissingBean(name = "xxxBeanName") 来定制 Bean 。

  • 需要先在Test配置之中创建Bean, 并指定Bean的名字。
  • 主配置之中则使用 @ConditionalOnMissingBean 注解来设置创建条件,避免冲突。

4. 测试代码

这里通过一个main方法来测试:


    public static void main(String[] args) {
        // 测试 execute 方法;
        CallerRunsExecutor.getInstance()
                .execute(new Runnable() {
                    @Override
                    public void run() {
                        System.out.println("execute run in " + Thread.currentThread().getName());
                    }
                });

        // 测试 submit 方法;
        Future<?> future = CallerRunsExecutor.getInstance()
                .submit(new Runnable() {
                    @Override
                    public void run() {
                        System.out.println("submit run in " + Thread.currentThread().getName());
                    }
                });

        try {
            Object result = future.get();
        } catch (Exception e) {
            e.printStackTrace();
        }
        // 正常输出
        System.out.println("main in " + Thread.currentThread().getName());

    }

5. 测试结果

测试结果为:

execute run in main
submit run in main
main in main

结果符合预期。

应用到我们的单元测试环境之中,也是符合预期的。

6. 相关问题

  • 1、注意限制使用环境, 不要影响生产;
  • 2、需要演示多个线程交互执行的某些代码可能会有问题;

日期: 2024年05月15日
作者: 铁锚 at CSDN

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值