自学内容网 自学内容网

Springboot使用ThreadPoolTaskScheduler轻量级多线程定时任务框架

简介: Spring注解定时任务使用不是很灵活,如果想要灵活的配置定时任务,可以使用xxl-job 或者 quartz等定时任务框架,但是过于繁琐,可能成本较大。所以可以使用ThreadPoolTaskScheduler来灵活处理定时任务

ThreadPoolTaskScheduler是什么

ThreadPoolTaskScheduler 是 Spring Framework 中的一部分,主要用于调度任务。它基于线程池,可以处理异步任务和定时任务

主要api

  • schedule(Runnable task, Trigger trigger) corn表达式,周期执行
  • schedule(Runnable task, Date startTime) 定时执行
  • scheduleAtFixedRate(Runnable task, Date startTime, long period)
    定时周期间隔时间执行。间隔时间单位 TimeUnit.MILLISECONDS
  • scheduleAtFixedRate(Runnable task, long period) 间隔时间以固定速率执行。单位毫秒

固定速率执行不会管上次执行的状态如何

在使用前需要配置下ThreadPoolTaskScheduler

@Configuration
public class SchedulingTaskConfig {

    @Bean(name = "myThreadPoolTaskScheduler")
    public ThreadPoolTaskScheduler threadPoolTaskScheduler(){
        ThreadPoolTaskScheduler taskScheduler = new ThreadPoolTaskScheduler();
        taskScheduler.setPoolSize(60);
        taskScheduler.setThreadNamePrefix("task-");
        taskScheduler.setAwaitTerminationSeconds(3000);
        taskScheduler.setWaitForTasksToCompleteOnShutdown(true);
        return taskScheduler;
    }
}

cron表达式


   @Override
    public String startTask() {
     ScheduledFuture<?> schedule = myThreadPoolTaskScheduler.schedule(new Runnable() {
            @Override
            public void run() {
                System.out.println("1s执行一次");
            }
        }, new CronTrigger("0/1 * * * * ?"));
    

定时执行一次

 myThreadPoolTaskScheduler.schedule(new Runnable() {
            @Override
            public void run() {
                System.out.println("定时执行3s后开始执行");
            }
        },new Date(System.currentTimeMillis() + 3000));

在固定时间以固定速率执行

 myThreadPoolTaskScheduler.scheduleAtFixedRate(new Runnable() {
            @Override
            public void run() {
                System.out.println("定时执行3s后开始执行,固定3s执行一次");
            }
        },new Date(System.currentTimeMillis() + 3000),3000);

任务取消

private  ScheduledFuture<?> schedule ;
    @Override
    public String startTask() {

         schedule = myThreadPoolTaskScheduler.scheduleAtFixedRate(new Runnable() {
            @Override
            public void run() {
                System.out.println("定时执行3s后开始执行,固定3s执行一次");
            }
        }, new Date(System.currentTimeMillis() + 3000), 3000);

        return "开启成功";
    }

    @Override
    public String stopTask() {
        if (schedule != null){
            schedule.cancel(true);
             System.out.println("任务取消成功");
            return "取消成功";
        }
        return "取消失败";
    }

实现页面控制定时任务开关

将定时任务保存到数据库中,并在页面上实现定时任务的开关,以及更新定时任务时间后重新创建定时任务

数据库实体




@TableName("task")
@Data
public class ScheduleTask {
    public interface Update{};

    @TableId(type = IdType.AUTO)
    @NotNull(message = "任务id不能为空",groups = Update.class)
    private Integer id;

    @NotBlank(message = "请填写任务执行类")
    @TableField("task_clazz")
    private String taskClazz;

    @NotBlank(message = "请填写任务执行方法")
    @TableField("task_method")
    private String taskMethod;

    @NotBlank(message = "请填写任务执行时间,采用cron格式")
    @TableField("cron")
    private String cron;

    @TableLogic
    @TableField("status")
    private Integer status;
}

contrloller

@RestController
@RequiredArgsConstructor
public class TaskManagerController {


    private final TaskManagerService taskManagerService;

    @PostMapping("/addTask")
    public Boolean addTask(@RequestBody @Validated ScheduleTask task){
        return taskManagerService.addTask(task);
    }

    @PostMapping("/stopTask/{id}")
    public Boolean stopTask(@PathVariable Integer id){
        return taskManagerService.stopTask(id);
    }
}

service



@Service
@Slf4j
@RequiredArgsConstructor
public class TaskManagerServiceImpl implements TaskManagerService {


    private final ScheduleTaskMapper scheduleTaskMapper;
    private final TaskManager taskManager;
    @Override
    public Boolean addTask(ScheduleTask task) {
        int i = scheduleTaskMapper.insert(task);
        if (i > 0){
            TaskRunnable taskRunnable = new TaskRunnable(task.getTaskClazz(), task.getTaskMethod());
            taskManager.addTask(String.valueOf(task.getId()),taskRunnable,task.getCron());
            return true;
        }
        return false;
    }

    @Override
    public Boolean stopTask(Integer id) {
        int i = scheduleTaskMapper.deleteById(id);
        if (i> 0){
            taskManager.stopTask(String.valueOf(id));
            return true;
        }
        return false;
    }
}

TaskRunnable

通过此类获取具体的执行方法



@Slf4j
public class TaskRunnable implements Runnable{
    /**
     * 定时任务类
     */
    private final String clazz;

    /**
     * 定时任务方法
     */
    private final String methodName;

    public TaskRunnable(String clazz, String methodName) {
        this.clazz = clazz;
        this.methodName = methodName;
    }

    @Override
    public void run() {

        try {
            //获取类
            Object bean = SpringContextUtils.getBean(clazz);
            //获取方法
           Method method = bean.getClass().getDeclaredMethod(methodName);
           //设置方法可用
           ReflectionUtils.makeAccessible(method);
           //执行方法
           method.invoke(bean);
        } catch (Exception e) {
            log.error("获取方法信息报错:{}",e.getMessage());
            throw new RuntimeException(e);
        }
    }
}

任务调度类



@Component
@RequiredArgsConstructor
@Slf4j
public class TaskManager {

    private final ThreadPoolTaskScheduler myThreadPoolTaskScheduler;

    public static ConcurrentHashMap<String, ScheduledFuture<?>> cache = new ConcurrentHashMap<>();

    /**
     * 创建定时任务
     * @param key 任务key
     * @param taskRunnable 当前线程
     * @param cron 定时任务cron
     */
    public void addTask(String key ,TaskRunnable taskRunnable ,String cron){
        //取消任务
        this.stopTask(key);
        ScheduledFuture<?> schedule = myThreadPoolTaskScheduler.schedule(taskRunnable, new CronTrigger(cron));
        if (schedule != null){
            cache.put(key,schedule);
            log.info("当key为{}的定时任务创建成功",key);
        }
    }


    public void stopTask(String key){
        if (cache.get(key) == null){
            log.info("当前没有key为{}的定时任务",key);
            return;
        }
        ScheduledFuture<?> scheduledFuture = cache.get(key);
        if (scheduledFuture != null){
            scheduledFuture.cancel(true);
            cache.remove(key);
            log.info("当前key为{}的定时任务已取消",key);
        }

    }
}

工具类




@Component
public class SpringContextUtils implements ApplicationContextAware {
    private static ApplicationContext context;
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) {
        SpringContextUtils.context = applicationContext;
    }

    public static Object getBean(String name){
        return context.getBean(name);
    }
}

方法测试


@Slf4j
@Component(value = "testTask")
public class TestTask {

    public void taskMethod(){
        log.info(String.format("调用了当前定时任务"));
    }
}


原文地址:https://blog.csdn.net/m0_73363097/article/details/142419944

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!