ThreadPoolTaskScheduler动态添加、移除定时任务

最近遇到一个需求,定时任务的业务逻辑不会改变,但需要动态添加、移除定时任务,而且定时执行时间有可能随时改变,这可怎么实现呢?
首先,配置定时任务线程池;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;

/**
 * 定时任务线程池配置类
 * @author 程就人生
 * @Date
 */
@Configuration
public class AsyncTheadConfig {
  
  @Bean("threadPoolTaskScheduler")
  public ThreadPoolTaskScheduler getThreadPoolTaskScheduler(){
    // 定时任务线程池
    ThreadPoolTaskScheduler executor = new ThreadPoolTaskScheduler();
    // 线程池大小
    executor.setPoolSize(10);
    // 线程执行前缀
    executor.setThreadNamePrefix("ThreadPoolTaskScheduler-");
    // executor.setWaitForTasksToCompleteOnShutdown(true);
    // executor.setAwaitTerminationSeconds(60);
    executor.initialize();
    return executor;
  }  
}

第二步,建立任务,里面包含了定时任务需要实现的业务逻辑;


import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;

/**
 * 定时任务的业务逻辑
 * @author 程就人生
 * @Date
 */
public class TimerThread implements Runnable{

  private String uid;
  
  public TimerThread(String uid){
    this.uid = uid;
  }
  
  @Override
  public void run() {
    ZonedDateTime zdt = ZonedDateTime.now();
    DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
    System.out.println(Thread.currentThread().getName() + " 任务:" + uid + ",执行时间:" + zdt.format(dtf));
  }
}

第三步,应用定时任务,包括添加、移除;

import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ScheduledFuture;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
import org.springframework.scheduling.support.CronTrigger;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RequestMapping("/index")
@RestController
public class IndexController1 {

  // 定时任务线程池
  @Autowired
  private ThreadPoolTaskScheduler threadPoolTaskScheduler;
    
  // 任务队列管理
  @SuppressWarnings("rawtypes")
  private ConcurrentHashMap<String, ScheduledFuture> futureMap = new ConcurrentHashMap<String, ScheduledFuture>();
    
   
  // 加入新的任务进来
  @SuppressWarnings({ "rawtypes" })
  @GetMapping("/insert/{uid}/{time}")
  public Object insert(@PathVariable("uid") String uid, @PathVariable("time") String time){
      // 定时任务执行类
      TimerThread timerCollectData = new TimerThread(uid);
      // 通过ThreadPoolTaskScheduler类,设定定时时间
      ScheduledFuture future = threadPoolTaskScheduler.schedule(timerCollectData, new CronTrigger("*/"+time+" * * * * ?"));
      // 加入到队列中
      futureMap.put(uid, future);
      return null;
  }
    
  // 移除已有的一个任务
  @SuppressWarnings("rawtypes")
  @GetMapping("/remove/{uid}")
  public Object remove(@PathVariable("uid") String uid){
      ScheduledFuture scheduledFuture = futureMap.get(uid);
      if(scheduledFuture != null){
         // 取消定时任务
         scheduledFuture.cancel(true);
         // 如果任务取消需要消耗点时间
         boolean cancelled = scheduledFuture.isCancelled();
          while (!cancelled) {

                scheduledFuture.cancel(true);
                System.out.println(uid + "取消中");
          }
          // 最后从队列中删除
          futureMap.remove(uid);
      }
      return null;
    }
}

最后,运行入口程序,打开浏览器进行测试;通过浏览器分别执行了localhost:8080/index/insert/1000/10、localhost:8080/index/insert/2000/20,也就是添加了两个任务,任务1000每10s执行一次,任务2000每20s执行一次;

执行 http://localhost:8080/index/remove/1000,把1000的任务移除掉,再看执行结果,只剩下任务2000,ok,动态添加、移除定时任务编码完成。

当然,这里为了测试,把管理任务的队列直接放到了Controller里,实际应用时应保持全局唯一。
最后总结

通过这个需求,我们又用到了一个类ThreadPoolTaskScheduler,它有别于ThreadPoolTaskExecutor类,有兴趣有时间的可以查看源码。

动态添加、移除定时任务的操作流程,大致可以分为以下四个步骤:

1.建立一个定时任务线程池;

2.为定时任务线程池建立一个队列,来管理这些任务;

3.根据唯一标识,往定时任务线程池和队列里分别添加这个任务;

4.根据唯一标识,从定时任务线程池里取消一个任务,并从队列里移除这个任务。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容