• 玩转SpringBoot之定时任务@Scheduled线程池配置


     

    阅读正文:

    序言

    对于定时任务,在SpringBoot中只需要使用@Scheduled 这个注解就能够满足需求,它的出现也给我们带了很大的方便,我们只要加上该注解,并且根据需求设置好就可以使用定时任务了。

    但是,我们需要注意的是,@Scheduled 并不一定会按时执行

    因为使用@Scheduled 的定时任务虽然是异步执行的,但是,不同的定时任务之间并不是并行的!!!!!!!!

    在其中一个定时任务没有执行完之前,其他的定时任务即使是到了执行时间,也是不会执行的,它们会进行排队。

    也就是如果你想你不同的定时任务互不影响,到时间就会执行,那么你最好将你的定时任务方法自己搞成异步方法,这样,定时任务其实就相当于调用了一个线程执行任务,一瞬间就结束了。比如使用:@Async

    当然,也可以勉强将你的定时任务当做都会定时执行。但是,作为一个合格的程序员

    那么,如何将@Scheduled实现的定时任务变成异步的呢?此时你需要对@Scheduled进行线程池配置。

    配置示例

    package com.java.navtool.business.config;
    
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.core.task.TaskExecutor;
    import org.springframework.scheduling.annotation.Async;
    import org.springframework.scheduling.annotation.EnableScheduling;
    import org.springframework.scheduling.annotation.SchedulingConfigurer;
    import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
    import org.springframework.scheduling.config.ScheduledTaskRegistrar;
    
    import java.util.concurrent.Executor;
    import java.util.concurrent.Executors;
    import java.util.concurrent.ThreadPoolExecutor;
    
    /**
     * @author :mmzsblog.cn
     * @date :Created in 2021/7/27 17:46
     * @description:spring-boot 多线程  @Scheduled注解 并发定时任务的解决方案
     * @modified By:
     * @version:
     */
    
    @Configuration
    @EnableScheduling
    public class ScheduleConfig implements SchedulingConfigurer {
    
        @Override
        public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
            taskRegistrar.setScheduler(taskExecutor());
        }
    
        public static final String EXECUTOR_SERVICE = "scheduledExecutor";
    
        @Bean(EXECUTOR_SERVICE)
        public TaskExecutor taskExecutor() {
            ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
            // 设置核心线程数
            executor.setCorePoolSize(Runtime.getRuntime().availableProcessors());
            // 设置最大线程数
            executor.setMaxPoolSize(Runtime.getRuntime().availableProcessors() * 10);
            // 设置队列容量
            executor.setQueueCapacity(Runtime.getRuntime().availableProcessors() * 10);
            // 设置线程活跃时间(秒)
            executor.setKeepAliveSeconds(10);
            // 设置默认线程名称
            executor.setThreadNamePrefix("scheduled-");
            // 设置拒绝策略
            executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
            // 等待所有任务结束后再关闭线程池
            executor.setWaitForTasksToCompleteOnShutdown(true);
            return executor;
        }
    
    }
    

    附带介绍一下线程池的几个参数。需要彻底搞懂,不要死记硬背哦!

    线程池参数

    • 1、corePoolSize(必填):核心线程数。
    • 2、maximumPoolSize(必填):最大线程数。
    • 3、keepAliveTime(必填):线程空闲时长。如果超过该时长,非核心线程就会被回收。
    • 4、unit(必填):指定keepAliveTime的时间单位。常用的有:TimeUnit.MILLISECONDS(毫秒)、TimeUnit.SECONDS(秒)、TimeUnit.MINUTES(分)。
    • 5、workQueue(必填):任务队列。通过线程池的execute()方法提交的Runnable对象将存储在该队列中。
    • 6、threadFactory(可选):线程工厂。一般就用默认的。
    • 7、handler(可选):拒绝策略。当线程数达到最大线程数时就要执行饱和策略。

    说下核心线程数和最大线程数的区别:

    拒绝策略可选值:

    • 1、AbortPolicy(默认):放弃任务并抛出RejectedExecutionException异常。
    • 2、CallerRunsPolicy:由调用线程处理该任务。
    • 3、DiscardPolicy:放弃任务,但是不抛出异常。可以配合这种模式进行自定义的处理方式。
    • 4、DiscardOldestPolicy:放弃队列最早的未处理任务,然后重新尝试执行任务。

    线程池执行流程:

    上个流程图,先试着自己看下能不能看懂:

    简短的总结下线程池执行流程:

    • 1、一个任务提交到线程池后,如果当前的线程数没达到核心线程数,则新建一个线程并且执行新任务,注意一点,这个新任务执行完后,该线程不会被销毁;
    • 2、如果达到了,则判断任务队列满了没,如果没满,则将任务放入任务队列;
    • 3、如果满了,则判断当前线程数量是否达到最大线程数,如果没达到,则创建新线程来执行任务,注意,如果线程池中线程数量大于核心线程数,每当有线程超过了空闲时间,就会被销毁,直到线程数量不大于核心线程数;
    • 4、如果达到了最大线程数,并且任务队列满了,就会执行饱和策略;



    作者:淼淼之森
    欢迎任何形式的转载,但请务必注明出处。
    如果你觉得本文还可以,那就点击一下推荐,让更多人看到吧!
    限于本人水平,如果文章和代码有表述不当之处,还请不吝赐教。

  • 相关阅读:
    flowable异步任务加锁流程
    mall :rabbit项目源码解析
    oracle 简易客户端上使用rman
    基于SSM的二手商品交易系统
    2022年RPA将从IT领域继续扩展至非IT领域,非IT领域5大场景RPA应用
    随想录一刷Day43——动态规划
    R语言使用pt函数生成t分布累积分布函数数据、使用plot函数可视化t分布累积分布函数数据(t Distribution)
    人机交互——自然语言生成
    Pyecharts数据可视化(一)
    Jquery入门和案例
  • 原文地址:https://www.cnblogs.com/mmzs/p/16057742.html