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
*/
@Deprecated
public 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;
}
/**
* 任务线程
*/
@Override
public void run() {
log.info("Task {} : is running ", "可以放Object里面的标识");
}
}
}