基于springboot,自定义线程池提高定时任务执行效率

基于springboot,自定义线程池提高定时任务执行效率

  • 在主类上开启@EnableScheduling和@EnableAsync以执行定时任务
/**
 * mallAdminApplication
 *
 * @author lyc
 **/
@EnableDubboConfiguration
@SpringBootApplication(exclude = {SpringBootConfiguration.class, DruidDataSourceAutoConfigure.class, DataSourceAutoConfiguration.class})
@EnableSwaggerAutoConfig
@EnableScheduling
public class MallAdminApplication {
    public static void main(String[] args) {
        SpringApplication.run(MallAdminApplication.class, args);
    }
} 
  • 配置线程池
/**
 * 线程池配置
 *
 * @author lyc
 **/
@Configuration
@Slf4j
public class ThreadPoolConfig {

    @Bean
    public Executor asyncServiceExecutor() {
        log.info("start asyncServiceExecutor");
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        //配置核心线程数
        executor.setCorePoolSize(5);
        //配置最大线程数
        executor.setMaxPoolSize(5);
        //配置队列大小
        executor.setQueueCapacity(99999);
        //配置线程池中的线程的名称前缀
        executor.setThreadNamePrefix("async-service-");

        // rejection-policy:当pool已经达到max size的时候,如何处理新任务
        // CALLER_RUNS:不在新线程中执行任务,而是有调用者所在的线程来执行
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        //执行初始化
        executor.initialize();
        return executor;
    }
} 
  • 以下模拟每隔一秒钟分别向两张表中插入数据,可用于向数据库中快速插入一些随机数据用于测试的需要
/**
 * 定时任务,用于添加测试数据
 *
 * @author lyc
 **/
@Component
@Slf4j
public class ScheduledTaskConfig {
    @Reference
    private IPmsProductService pmsProductService;
    @Reference
    private IOmsOrderService omsOrderService;
    @Reference
    private IUmsMemberService umsMemberService;
    private Snowflake snowflake = IdUtil.getSnowflake(1L, 1L);

    /**
    *使用自定义的线程池执行任务
    **/
    @Autowired
    @Qualifier("asyncServiceExecutor")
    private Executor executor;

    @Scheduled(cron = "*/1 * * * * ?")
    @Async("asyncServiceExecutor")
    public void scheduledInsertPmsProduct() {
        for (int i = 0; i < 100; i++) {
            CompletableFuture.runAsync(() -> {
                String randomUUID = IdUtil.randomUUID();
                String name = "商品名称" + randomUUID;
                log.info(">>>>>>>>>>>>>开始插入商品数据: {}", name);
                pmsProductService.save(new PmsProduct().setName(name)
                        .setDescription("商品描述" + randomUUID)
                        .setProductSn("no" + randomUUID));
            }, executor);
        }
    }

    @Scheduled(cron = "*/1 * * * * ?")
    @Async("asyncServiceExecutor")
    public void scheduledInsertUmsMember() {
        for (int i = 0; i < 100; i++) {
            CompletableFuture.runAsync(() -> {
                String snowflakeStr = snowflake.nextIdStr();
                String name = "user" + snowflakeStr;
                String nickname = "昵称" + snowflakeStr;
                Random random = new Random();
                log.info(">>>>>>>>>>>>>开始插入用户数据: {}", name);

                umsMemberService.save(new UmsMember()
                        .setNickname(nickname)
                        .setUsername(name)
                        .setPassword(snowflakeStr)
                        .setGender(random.nextInt(3)));
            }, executor);
        }
    }


}
线程池的任务执行机制

任务调度是线程池的主要入口,当用户提交了一个任务,接下来这个任务将如何执行都是由这个阶段决定的。了解这部分就相当于了解了线程池的核心运行机制。

首先,所有任务的调度都是由execute方法完成的,这部分完成的工作是:检查现在线程池的运行状态、运行线程数、运行策略,决定接下来执行的流程,是直接申请线程执行,或是缓冲到队列中执行,亦或是直接拒绝该任务。其执行过程如下:

首先检测线程池运行状态,如果不是RUNNING,则直接拒绝,线程池要保证在RUNNING的状态下执行任务。
如果workerCount < corePoolSize,则创建并启动一个线程来执行新提交的任务。
如果workerCount >= corePoolSize,且线程池内的阻塞队列未满,则将任务添加到该阻塞队列中。
如果workerCount >= corePoolSize && workerCount < maximumPoolSize,且线程池内的阻塞队列已满,则创建并启动一个线程来执行新提交的任务。
如果workerCount >= maximumPoolSize,并且线程池内的阻塞队列已满, 则根据拒绝策略来处理该任务, 默认的处理方式是直接抛异常。

参考:https://tech.meituan.com/2020/04/02/java-pooling-pratice-in-meituan.html

你可能感兴趣的:(基于springboot,自定义线程池提高定时任务执行效率)