Spirng 定时任务 和 异步任务

1-定时任务

/**
 * 定时任务
 *      1、@EnableScheduling 开启定时任务
 *      2、@Scheduled开启一个定时任务
 */

1-1源码解读

自动配置类TaskSchedulingAutoConfiguration,源码如下

@ConditionalOnClass({ThreadPoolTaskScheduler.class})
@Configuration
@EnableConfigurationProperties({TaskSchedulingProperties.class})
@AutoConfigureAfter({TaskExecutionAutoConfiguration.class})
public class TaskSchedulingAutoConfiguration {
    public TaskSchedulingAutoConfiguration() {
    }

    @Bean
    @ConditionalOnBean(
        name = {"org.springframework.context.annotation.internalScheduledAnnotationProcessor"}
    )
    @ConditionalOnMissingBean({SchedulingConfigurer.class, TaskScheduler.class, ScheduledExecutorService.class})
    public ThreadPoolTaskScheduler taskScheduler(TaskSchedulerBuilder builder) {
        return builder.build();
    }

    @Bean
    @ConditionalOnMissingBean
    public TaskSchedulerBuilder taskSchedulerBuilder(TaskSchedulingProperties properties, ObjectProvider<TaskSchedulerCustomizer> taskSchedulerCustomizers) {
        TaskSchedulerBuilder builder = new TaskSchedulerBuilder();
        builder = builder.poolSize(properties.getPool().getSize());
        builder = builder.threadNamePrefix(properties.getThreadNamePrefix());
        builder = builder.customizers(taskSchedulerCustomizers);
        return builder;
    }
}

1-2 配置类

注解@EnableConfigurationProperties({TaskSchedulingProperties.class}) 中

,TaskSchedulingProperties 是其默认配置,代码就不贴出,主要是

  • 线程名称前缀:threadNamePrefix = “scheduling-”
  •  线程数:size = 1   默认是单线程

2-异步任务 任务执行器 TaskExecutor

/**
 *
 * 异步任务
 *      1、@EnableAsync:开启异步任务
 *      2、@Async:给希望异步执行的方法标注
 *      TaskExecutionAutoConfiguration
 */

2-1自动配置类 TaskExecutionAutoConfiguration,源码如下

@ConditionalOnClass({ThreadPoolTaskExecutor.class})
@Configuration
@EnableConfigurationProperties({TaskExecutionProperties.class})
public class TaskExecutionAutoConfiguration {
    public static final String APPLICATION_TASK_EXECUTOR_BEAN_NAME = "applicationTaskExecutor";
    private final TaskExecutionProperties properties;
    private final ObjectProvider<TaskExecutorCustomizer> taskExecutorCustomizers;
    private final ObjectProvider<TaskDecorator> taskDecorator;

    public TaskExecutionAutoConfiguration(TaskExecutionProperties properties, ObjectProvider<TaskExecutorCustomizer> taskExecutorCustomizers, ObjectProvider<TaskDecorator> taskDecorator) {
        this.properties = properties;
        this.taskExecutorCustomizers = taskExecutorCustomizers;
        this.taskDecorator = taskDecorator;
    }

    @Bean
    @ConditionalOnMissingBean
    public TaskExecutorBuilder taskExecutorBuilder() {
        Pool pool = this.properties.getPool();
        TaskExecutorBuilder builder = new TaskExecutorBuilder();
        builder = builder.queueCapacity(pool.getQueueCapacity());
        builder = builder.corePoolSize(pool.getCoreSize());
        builder = builder.maxPoolSize(pool.getMaxSize());
        builder = builder.allowCoreThreadTimeOut(pool.isAllowCoreThreadTimeout());
        builder = builder.keepAlive(pool.getKeepAlive());
        builder = builder.threadNamePrefix(this.properties.getThreadNamePrefix());
        builder = builder.customizers(this.taskExecutorCustomizers);
        builder = builder.taskDecorator((TaskDecorator)this.taskDecorator.getIfUnique());
        return builder;
    }

    @Lazy
    @Bean(
        name = {"applicationTaskExecutor", "taskExecutor"}
    )
    @ConditionalOnMissingBean({Executor.class})
    public ThreadPoolTaskExecutor applicationTaskExecutor(TaskExecutorBuilder builder) {
        return builder.build();
    }
}

2-2 配置类

其默认配置类  @EnableConfigurationProperties({TaskExecutionProperties.class})中,

TaskExecutionProperties 主要配置

  • 线程名称前缀:threadNamePrefix = “task-”
  • 核心线程数:coreSize = 8
  • 最大线程数:maxSize = Integer.MAX_VALUE
  • 非核心线程存活时长:keepAlive = Duration.ofSeconds(60)

3-代码演示DEMO 以及配置

   /**
     *1、在spring中cron6位组成,不允许第七位年
     *2、在周的位置,1-7代表周一到周日或MON-SUN
     *3、定时任务不应该阻塞。默认是阻塞的

            实现定时任务不阻塞的方式:
     *      3.1、可以让业务以异步的方式运行,自己提交到线程池
     *      3.2、使用定时任务自带的线程池
     *          定时任务自带线程池的线程数:spring.task.scheduling.pool.size=5
     *          有些springboot版本设置了这个也不好使,可能是bug
     *      3.3、让定时任务异步执行,直接让整个定时任务方法异步执行,而不是方法里的业务异步执行
     *           springboot提供了异步任务的功能,除了我们自己写一个线程池,把我们自己要执行的
     *           业务丢给线程池执行之外,springboot还支持异步任务
     *           一、类上加注解@EnableAsync,开启异步任务
     *           二、给要异步执行的方法标上注解@Async
     *
     *
     *
     */

 @EnableAsync //开始异步
 @EnableScheduling //开始定时任务
public class TestTask {

 
    //1-定时任务
    @Scheduled(cron = "0 * * * * ?")
    public void test() throws InterruptedException {
      log.warn("Scheduled1",Thread.currentThread().getId(),Thread.currentThread().getName());
        Thread.sleep(1000);
    }

    //2- 异步定时任务
    @Async // 开启异步
    @Scheduled(cron = "0 * * * * ?")
    public void test2() throws InterruptedException {
     log.warn("Scheduled2",Thread.currentThread().getId(),Thread.currentThread().getName());
        Thread.sleep(1000);
    }
}

 3-1定时任务yml配置文件详解

spring:
  task:
    # Spring 同步任务执行配置
    scheduling:
      pool:
        size: 5 # 线程池大小。默认为 1 ,根据自己应用来设置
      shutdown:
        await-termination: false # 应用关闭时,是否等待定时任务执行完成。默认为 false ,建议设置为 true
        await-termination-period: 60 # 等待任务完成的最大时长,单位为秒。默认为 0 ,根据自己应用来设置
      thread-name-prefix: scheduling- # 线程池的线程名的前缀。默认为 scheduling- ,建议根据自己应用来设置
    # Spring 执行器配置,对应 TaskExecutionProperties 配置类。对于 Spring 异步任务,会使用该执行器。
    execution:
      thread-name-prefix: async-task- # 线程池的线程名的前缀。默认为 task- ,建议根据自己应用来设置
      pool: # 线程池相关
        core-size: 8 # 核心线程数,线程池创建时候初始化的线程数。默认为 8 。
        max-size: 20 # 最大线程数,线程池最大的线程数,只有在缓冲队列满了之后,才会申请超过核心线程数的线程。默认为 Integer.MAX_VALUE
        keep-alive: 60s # 允许线程的空闲时间,当超过了核心线程之外的线程,在空闲时间到达之后会被销毁。默认为 60 秒
        queue-capacity: 200 # 缓冲队列大小,用来缓冲执行任务的队列的大小。默认为 Integer.MAX_VALUE 。
        allow-core-thread-timeout: true # 是否允许核心线程超时,即开启线程池的动态增长和缩小。默认为 true 。
      shutdown:
        await-termination: true # 应用关闭时,是否等待定时任务执行完成。默认为 false ,建议设置为 true
        await-termination-period: 60 # 等待任务完成的最大时长,单位为秒。默认为 0 ,根据自己应用来设置

 4-分布式事务下定时任务

三台机器A1,A2,A3,都有一个定时任务,同一段程序,定时任务的设置都一样,等时间一到,它们就都同时启动了定时任务,就要同时执行业务代码,就会出现幂等性问题

 解决方式:
应该是定时任务,只能有一台机器在执行,不能所有机器同时执行,使用分布式锁可以解决。

演示DEMO:


@Service
public class seckillSkuScheduled {
    @Autowired
    private SeckillService seckillService;
    @Autowired
    private RedissonClient redissionClient;

    private final String upload_lock="seckill:upload:lock";

    //保证幂等性问题
    @Scheduled(cron = "*/5 * * * * ?")
    public void uploadSeckillSkuLatest3Days() {
        log.info("上架秒杀的商品");

        //分布式锁
        RLock lock = redissionClient.getLock(upload_lock);
        //锁的超时时间
        lock.lock(10, TimeUnit.SECONDS);
        try{
            seckillService.uploadSeckillSkuLatest3Days();
        }finally {
            //释放锁
            lock.unlock();
        }
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值