本文描述的使用 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管理,然后在需要的地方注入即可
@Bean
public CustomScheduledTaskManager customScheduledTaskManager() {
return new CustomScheduledTaskManager();
}
@Resource
private CustomScheduledTaskManager customScheduledTaskManager;
@PostConstruct
private 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------>");
});
}