ThreadPoolTaskScheduler動(dòng)態(tài)添加、移除定時(shí)任務(wù)

最近遇到一個(gè)需求,定時(shí)任務(wù)的業(yè)務(wù)邏輯不會(huì)改變,但需要?jiǎng)討B(tài)添加、移除定時(shí)任務(wù),而且定時(shí)執(zhí)行時(shí)間有可能隨時(shí)改變,這可怎么實(shí)現(xiàn)呢?
首先,配置定時(shí)任務(wù)線(xiàn)程池;

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

/**
 * 定時(shí)任務(wù)線(xiàn)程池配置類(lèi)
 * @author 程就人生
 * @Date
 */
@Configuration
public class AsyncTheadConfig {
  
  @Bean("threadPoolTaskScheduler")
  public ThreadPoolTaskScheduler getThreadPoolTaskScheduler(){
    // 定時(shí)任務(wù)線(xiàn)程池
    ThreadPoolTaskScheduler executor = new ThreadPoolTaskScheduler();
    // 線(xiàn)程池大小
    executor.setPoolSize(10);
    // 線(xiàn)程執(zhí)行前綴
    executor.setThreadNamePrefix("ThreadPoolTaskScheduler-");
    // executor.setWaitForTasksToCompleteOnShutdown(true);
    // executor.setAwaitTerminationSeconds(60);
    executor.initialize();
    return executor;
  }  
}

第二步,建立任務(wù),里面包含了定時(shí)任務(wù)需要實(shí)現(xiàn)的業(yè)務(wù)邏輯;


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

/**
 * 定時(shí)任務(wù)的業(yè)務(wù)邏輯
 * @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() + " 任務(wù):" + uid + ",執(zhí)行時(shí)間:" + zdt.format(dtf));
  }
}

第三步,應(yīng)用定時(shí)任務(wù),包括添加、移除;

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 {

  // 定時(shí)任務(wù)線(xiàn)程池
  @Autowired
  private ThreadPoolTaskScheduler threadPoolTaskScheduler;
    
  // 任務(wù)隊(duì)列管理
  @SuppressWarnings("rawtypes")
  private ConcurrentHashMap<String, ScheduledFuture> futureMap = new ConcurrentHashMap<String, ScheduledFuture>();
    
   
  // 加入新的任務(wù)進(jìn)來(lái)
  @SuppressWarnings({ "rawtypes" })
  @GetMapping("/insert/{uid}/{time}")
  public Object insert(@PathVariable("uid") String uid, @PathVariable("time") String time){
      // 定時(shí)任務(wù)執(zhí)行類(lèi)
      TimerThread timerCollectData = new TimerThread(uid);
      // 通過(guò)ThreadPoolTaskScheduler類(lèi),設(shè)定定時(shí)時(shí)間
      ScheduledFuture future = threadPoolTaskScheduler.schedule(timerCollectData, new CronTrigger("*/"+time+" * * * * ?"));
      // 加入到隊(duì)列中
      futureMap.put(uid, future);
      return null;
  }
    
  // 移除已有的一個(gè)任務(wù)
  @SuppressWarnings("rawtypes")
  @GetMapping("/remove/{uid}")
  public Object remove(@PathVariable("uid") String uid){
      ScheduledFuture scheduledFuture = futureMap.get(uid);
      if(scheduledFuture != null){
         // 取消定時(shí)任務(wù)
         scheduledFuture.cancel(true);
         // 如果任務(wù)取消需要消耗點(diǎn)時(shí)間
         boolean cancelled = scheduledFuture.isCancelled();
          while (!cancelled) {

                scheduledFuture.cancel(true);
                System.out.println(uid + "取消中");
          }
          // 最后從隊(duì)列中刪除
          futureMap.remove(uid);
      }
      return null;
    }
}

最后,運(yùn)行入口程序,打開(kāi)瀏覽器進(jìn)行測(cè)試;通過(guò)瀏覽器分別執(zhí)行了localhost:8080/index/insert/1000/10、localhost:8080/index/insert/2000/20,也就是添加了兩個(gè)任務(wù),任務(wù)1000每10s執(zhí)行一次,任務(wù)2000每20s執(zhí)行一次;

執(zhí)行 http://localhost:8080/index/remove/1000,把1000的任務(wù)移除掉,再看執(zhí)行結(jié)果,只剩下任務(wù)2000,ok,動(dòng)態(tài)添加、移除定時(shí)任務(wù)編碼完成。

當(dāng)然,這里為了測(cè)試,把管理任務(wù)的隊(duì)列直接放到了Controller里,實(shí)際應(yīng)用時(shí)應(yīng)保持全局唯一。
最后總結(jié)

通過(guò)這個(gè)需求,我們又用到了一個(gè)類(lèi)ThreadPoolTaskScheduler,它有別于ThreadPoolTaskExecutor類(lèi),有興趣有時(shí)間的可以查看源碼。

動(dòng)態(tài)添加、移除定時(shí)任務(wù)的操作流程,大致可以分為以下四個(gè)步驟:

1.建立一個(gè)定時(shí)任務(wù)線(xiàn)程池;

2.為定時(shí)任務(wù)線(xiàn)程池建立一個(gè)隊(duì)列,來(lái)管理這些任務(wù);

3.根據(jù)唯一標(biāo)識(shí),往定時(shí)任務(wù)線(xiàn)程池和隊(duì)列里分別添加這個(gè)任務(wù);

4.根據(jù)唯一標(biāo)識(shí),從定時(shí)任務(wù)線(xiàn)程池里取消一個(gè)任務(wù),并從隊(duì)列里移除這個(gè)任務(wù)。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀(guān)點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容