本文描述的使用 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------>");});}