定时任务线池备忘
- 1、定时任务线程池选型
- 2、ThreadPoolTaskScheduler使用
1、定时任务线程池选型
Java常用的定时任务池方案有:
- Java自带
ScheduledExecutorService 、ThreadPoolTaskScheduler。主要区别在于对定时的方式的支持不一样。ThreadPoolTaskScheduler调用还是ScheduledExecutorService。
- 框架
Quartz :Quartz 支持基于日历的作业调度,允许用户创建多个触发器(Trigger)来定义单个作业(Job)的计划。Quartz 也提供了一个基于 JDBC 的存储机制,将作业的配置信息保存在数据库中,以支持分布式部署。Quartz 还具有良好的可扩展性和灵活性,支持集群部署和动态加载作业定义等功能。
Spring Task:是 Spring 框架提供的一种轻量级的任务调度框架,简化了异步任务的创建和调度过程。Spring Task 支持使用注解配置定时任务,并提供了 CronTrigger 和 SimpleTrigger 等多种触发器类型。可以通过 Spring Task 来执行简单的定时任务,也可以使用它来创建复杂的任务流程和并发作业。
因为短平快,只让部署一台一个应用,使用ScheduledExecutorService够了
2、ThreadPoolTaskScheduler使用
上次使用的是ThreadPoolTaskScheduler方法。
定时任务线程池对象的创建如下,使用单例保证只存在一个定时任务池。
注意多线程下单例问题
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;/*** 定时任务线程池创建工具类** @since 2022/10/16*/
public class TaskExecutors {/*** 创建定时任务池*/private static final ScheduledExecutorService scheduledThreadPoolExecutor = Executors.newScheduledThreadPool(5);private static final ThreadPoolTaskScheduler threadPoolTaskScheduler = new ThreadPoolTaskScheduler();static {threadPoolTaskScheduler.setPoolSize(20);threadPoolTaskScheduler.setThreadNamePrefix("CollectSetTaskExecutor-");threadPoolTaskScheduler.initialize();}private TaskExecutors() {}/*** 创建定时任务池(常驻线程)** @return*/@Deprecatedpublic static ScheduledExecutorService getScheduledThreadPool() {return scheduledThreadPoolExecutor;}/*** 创建定时任务池(常驻线程)** @return*/public static ThreadPoolTaskScheduler getThreadPoolTaskScheduler() {return threadPoolTaskScheduler;}
}
import cn.hutool.json.JSONUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.support.CronTrigger;
import org.springframework.stereotype.Component;import java.text.SimpleDateFormat;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ScheduledFuture;/*** 定时任务** @since 2022/10/17*/
@Slf4j
@Component
public class CollectSetTask {private final SimpleDateFormat sDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");/*** key:value 对应* 自定义标识 : thread ScheduleFuture* <p>* 用于存储定时任务状态*/private Map<String, ScheduledFuture> threadMap = new HashMap<>();/*** 执行定时任务,如果定时任务已存在,则清除并重新启动** @param yourTaskObject 信息对象*/public void start(Object yourTaskObject) {String timer = "";String id = "";log.info("Perform tasks immediately at startup:{}", id);// 下面调用schedule方法就是加入定时线程池了,此处作用在于调用本方法后立即执行一次任务new Thread(new YourTaskExecutor(yourTaskObject)).start();// 如果定时任务已存在则清除stopById(id);if (null != threadMap.get(id)) {threadMap.get(id).cancel(true);}// 执行线程并更新状态ScheduledFuture<?> schedule = TaskExecutors.getThreadPoolTaskScheduler().schedule(new YourTaskExecutor(yourTaskObject), new CronTrigger(timer));threadMap.put(id, schedule);log.info("CollectSetTask {} : stars", id);}/*** 停止线程任务** @param request 请求对象*/public void stop(String id) {//获取前端数据log.info("========Start to stop the collectSetTask========");stopById(id);}/*** 依据任务ID停止线程任务** @param id 任务ID*/private void stopById(String id) {if (null != threadMap.get(id)) {threadMap.get(id).cancel(true);}log.info("{} CollectSet task is remove", id);}/*** 任务正在运行返回true,没有在运行返回false** @param id* @return*/public boolean status(String id) {ScheduledFuture scheduledFuture = threadMap.get(id);if (null == scheduledFuture) {return false;}return scheduledFuture.isDone();}/*** 返回所有定时任务状态* 任务正在运行返回true,没有在运行返回false** @return*/public Map<String, Boolean> statusAll() {Set<String> idSet = threadMap.keySet();HashMap<String, Boolean> statusMap = new HashMap<>();for (String id : idSet) {ScheduledFuture scheduledFuture = threadMap.get(id);statusMap.put(id, null != scheduledFuture && !scheduledFuture.isDone());}log.info("当前所有定时任务状态为:{}", JSONUtil.toJsonStr(statusMap));return statusMap;}/*** 采集SQL执行线程*/private class YourTaskExecutor implements Runnable {private Object object;public YourTaskExecutor(Object object) {this.object = object;}/*** 任务线程*/@Overridepublic void run() {log.info("Task {} : is running ", "可以放Object里面的标识");}}
}