阅读 238

SpringBoot 整合定时任务与线程池

在工作中遇到这样一个需求,“在每个工作日的【11:15、14:15、16:15、18:00】定时提醒”,该需求中存在两个难点:

  • 每日时间是固定的,并且不是周期循环,只能配置在固定的时间点进行执行
  • 在工作日执行,这就存在需要排除周六、天,排除节假日,可能还存在周六、日补班的情况等。

此处对工作日的处理只通过程序排除周六、日。对节假日暂不进行处理,但思路是如果对节假日进行处理只能进行人工配置的方式,例如将每年的节假日和周末补班的情况预先配置到数据库表或缓存(Redis)中,定时任务每次执行时先进行判断。

代码结构自上而下

主启动类

此处主要需要注意的是需要添加 @EnableScheduling 注解进行开启,否则定时任务不生效。

package com.lx.dca.okr.batch;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableScheduling;

/**
* 启动类
* @author wangcp
* @date 2021/05/07 17:04
**/
@SpringBootApplication
@EnableScheduling
public class BatchApplication {
    public static void main(String[] args) {
        SpringApplication.run(BatchApplication.class , args);
    }
}

定时任务执行类

此处需要注意类上添加 @Component 注解进行注入,否则定时任务不执行

package com.lx.dca.okr.batch.task;

import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.scheduling.annotation.Schedules;
import org.springframework.stereotype.Component;

import java.text.SimpleDateFormat;
import java.util.Date;

/**
* 定时提醒类
* @author wangcp
* @date 2021/05/08 18:04
**/
@Component
public class TimingRemindTask {

//    @Schedules({@Scheduled(cron = "0 15 11,14,16 * * ? "),@Scheduled(cron = "0 0 18 * * ? ")})
    @Schedules({@Scheduled(cron = "0 0/3 9 * * ? "),@Scheduled(cron = "0 40,45,50,55 9 * * ? ")})
    public void remindTask(){
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        System.out.println("执行定时任务了,执行时间为:" + sdf.format(new Date()));
    }
}

被注释掉的 @Schedules 是根据开头需求【11:15、14:15、16:15、18:00】设定的,但为了方便测试,定义了从9:00开始每3分钟执行一次和从9:00开始9:40、9:45、9:50、9:55执行,执行结果如下图所示:

image-20210510100234397.png

现在定时任务的问题已经解决了,但还需要排除周六和周日。解决的思路为执行定时任务时,判断当前是否为周六或周日,不是则正常执行,反之则跳过此次任务。

添加判断代码

package com.lx.dca.okr.batch.task;

import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.scheduling.annotation.Schedules;
import org.springframework.stereotype.Component;

import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;

/**
* 定时提醒类
* @author wangcp
* @date 2021/05/08 18:04
**/
@Component
public class TimingRemindTask {

//    @Schedules({@Scheduled(cron = "0 15 11,14,16 * * ? "),@Scheduled(cron = "0 0 18 * * ? ")})
    @Schedules({@Scheduled(cron = "0 0/1 * * * ?  "),@Scheduled(cron = "0 40,45,50,55 9 * * ? ")})
    public void remindTask(){
        Date date = new Date();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        // 不为周末时进行执行
        if(this.isWeekends(date)){
            System.out.println("执行定时任务了,执行时间为:" + sdf.format(date));
        }
    }


    /**
    * 根据传入时间进行判断,若为周六日则返回false,否则返回true
    * @author wangcp
    * @date 2021/05/10 10:24
     * @param date
    * @return boolean
    */
    private boolean isWeekends(Date date){
        Calendar instance = Calendar.getInstance();
        instance.setTime(date);
        if(instance.get(Calendar.DAY_OF_WEEK) == Calendar.SATURDAY || instance.get(Calendar.DAY_OF_WEEK) == Calendar.SUNDAY){
            return false;
        }
        return true;
    }

}

添加线程池

线程池配置类

有关线程池不做详细介绍,前面有专门介绍线程池的文章。

package com.lx.dca.okr.batch.config;

import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.task.TaskExecutor;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;

import java.util.concurrent.ThreadPoolExecutor;

/**
* 线程池配置类
* @author wangcp
* @date 2021/05/08 17:56
**/
@Data
@EnableAsync
@Configuration
@ConfigurationProperties(prefix = "poolconfig")
public class ThreadPoolConfig {
    /**
     * 线程池维护线程的最少数量,即使没有任务需要执行,也会一直存活
     */
    private int corePoolSize;

    /**
     * 线程池维护线程的最大数量
     */
    private int maxPoolSize;

    /**
     * 缓存队列(阻塞队列)当核心线程数达到最大时,新任务会放在队列中排队等待执行
     */
    private int queueCapacity;

    /**
     * 允许的空闲时间,当线程空闲时间达到keepAliveTime时,线程会退出,直到线程数量=corePoolSize
     */
    private int keepAlive;

    @Bean
    public TaskExecutor taskExecutor(){
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        //设置核心线程数
        executor.setCorePoolSize(corePoolSize);
        // 设置最大线程数
        executor.setMaxPoolSize(maxPoolSize);
        // 设置队列容量
        executor.setQueueCapacity(queueCapacity);
        // 设置允许的空闲时间(秒)
        executor.setKeepAliveSeconds(keepAlive);
        // 设置默认线程名称
        executor.setThreadNamePrefix("thread-");
        // 设置拒绝策略rejection-policy:当pool已经达到max size的时候,如何处理新任务
        // CALL_RUNS:不在新线程中执行任务,二十由调用者所在的线程来执行
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        // 等待所有任务结束后在关闭线程池
        executor.setWaitForTasksToCompleteOnShutdown(true);
        return executor;
    }
}

任务接口与实现类

TaskService

package com.lx.dca.okr.batch.service;

public interface TaskService {
    void executeRemindMessage() throws InterruptedException;
}

TaskServiceImpl

package com.lx.dca.okr.batch.service.impl;

import com.lx.dca.okr.batch.service.TaskService;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import java.text.SimpleDateFormat;
import java.util.Date;

/**
* 定时任务执行类
* @author wangcp
* @date 2021/05/10 10:42
**/
@Service
public class TaskServiceImpl implements TaskService {

    @Async("taskExecutor")
    @Override
    public void executeRemindMessage() throws InterruptedException {
        Date date = new Date();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        System.out.println("当前运行线的程名称:" + Thread.currentThread().getName() + " ,执行定时任务了,执行时间为:" + sdf.format(date));
        Thread.sleep(1500);
    }
}

执行结果如下:

image-20210510110433844.png

作者:大程子的技术成长路

原文链接:https://www.jianshu.com/p/0bb73ab224fb

文章分类
后端
版权声明:本站是系统测试站点,无实际运营。本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 XXXXXXo@163.com 举报,一经查实,本站将立刻删除。
相关推荐