本文描述的使用 Java 自带的 ScheduledExecutorService
来实现这个业务,直接看代码
涉及到的参数说明:
- ScheduledTaskManager 类负责管理定时任务的创建、取消和重设。
- scheduleTask 方法用于创建定时任务。它接受任务名称、开始时间、执行间隔和任务本身作为参数。
- cancelTask 方法用于取消定时任务。
- rescheduleTask 方法用于重设定时任务,它先取消原有任务,然后使用新的参数创建新的任务。
- getInitialDelay 方法计算从当前时间到开始时间的延迟时间(秒)。
import cn.hutool.core.date.DateUtil;
import lombok.extern.slf4j.Slf4j;
import java.time.Duration;
import java.time.LocalDateTime;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;@Slf4j
public class CustomScheduledTaskManager {private final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);private final Map<String, ScheduledFuture<?>> scheduledTasks = new ConcurrentHashMap<>();/*** 执行定时任务* @param taskName* @param startTime* @param intervalDays* @param task*/public void scheduleTask(String taskName, LocalDateTime startTime, int intervalDays, Runnable task){log.info("CustomScheduledTaskManager task '{}' to run at {} every {} days========>", taskName, DateUtil.format(startTime, "yyyy-MM-dd HH:mm:ss"), intervalDays);long initialDelay = getInitialDelay(startTime, intervalDays);ScheduledFuture<?> future = scheduler.scheduleAtFixedRate(task, initialDelay, intervalDays * 24 * 60 * 60, TimeUnit.SECONDS);scheduledTasks.put(taskName, future);}/*** 取消任务* @param taskName*/public void cancelTask(String taskName) {log.info("CustomScheduledTaskManager task '{}' to cannel========>");ScheduledFuture<?> task = scheduledTasks.get(taskName);if (task != null) {task.cancel(true);scheduledTasks.remove(taskName);}}/*** 重新调度任务* @param taskName* @param newStartTime* @param newIntervalDays* @param task*/public void rescheduleTask(String taskName, LocalDateTime newStartTime, int newIntervalDays, Runnable task) {cancelTask(taskName);scheduleTask(taskName, newStartTime, newIntervalDays, task);}/*** 计算延迟时间* @param startTime 任务执行时间* @return*/private long getInitialDelay(LocalDateTime startTime) {LocalDateTime now = LocalDateTime.now();long seconds = startTime.toEpochSecond(java.time.ZoneOffset.UTC) - now.toEpochSecond(java.time.ZoneOffset.UTC);return seconds > 0 ? seconds : 0;}/*** 计算延迟时间* @param startTime 任务执行时间* @param intervalDays 延迟N天* @return*/public static long getInitialDelay(LocalDateTime startTime, int intervalDays) {LocalDateTime endDateTime = LocalDateTime.now();long totalSeconds = Duration.between(startTime, endDateTime).getSeconds();if(totalSeconds < 0){return Math.abs(totalSeconds);}//long totalDays = totalSeconds / (24 * 60 * 60);//long fullNDayPeriods = totalDays / intervalDays;long remainingSeconds = totalSeconds % (intervalDays * 24 * 60 * 60);long additionalSeconds = intervalDays * 24 * 60 * 60 - remainingSeconds;return additionalSeconds;}
}
首先交给Bean管理,然后在需要的地方注入即可
@Beanpublic CustomScheduledTaskManager customScheduledTaskManager() {return new CustomScheduledTaskManager();}@Resourceprivate CustomScheduledTaskManager customScheduledTaskManager;@PostConstructprivate void init() {log.info("定时任务初始化========>"); customScheduledTaskManager.scheduleTask(confConfig.getFieldKey(), confConfig.getGmtModified().toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime(), Integer.valueOf(confConfig.getFieldValue()), () -> {log.info("定时任务执行========>start------>");this.noticeManageService.timingPush();log.info("定时任务执行========>end------>");});}