diff --git a/src/main/java/xyz/wbsite/jmacro/JMainService.java b/src/main/java/xyz/wbsite/jmacro/JMainService.java index 9706a6a..4bfe669 100644 --- a/src/main/java/xyz/wbsite/jmacro/JMainService.java +++ b/src/main/java/xyz/wbsite/jmacro/JMainService.java @@ -1,7 +1,6 @@ package xyz.wbsite.jmacro; import cn.hutool.core.collection.CollUtil; -import org.jobrunr.jobs.lambdas.JobLambda; import xyz.wbsite.jmacro.base.Legend; import xyz.wbsite.jmacro.util.DialogUtil; import xyz.wbsite.jmacro.util.Logger; diff --git a/src/main/java/xyz/wbsite/jmacro/JScheduler.java b/src/main/java/xyz/wbsite/jmacro/JScheduler.java index b7523a9..b21351b 100644 --- a/src/main/java/xyz/wbsite/jmacro/JScheduler.java +++ b/src/main/java/xyz/wbsite/jmacro/JScheduler.java @@ -3,9 +3,13 @@ package xyz.wbsite.jmacro; import java.time.LocalTime; import java.time.format.DateTimeFormatter; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; import java.util.Map; +import java.util.Queue; import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentLinkedQueue; +import java.util.concurrent.ConcurrentSkipListSet; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ScheduledFuture; @@ -31,88 +35,108 @@ public class JScheduler { /** * 任务映射表,用于存储任务ID和对应的 ScheduledFuture 对象 */ - private final Map> tasks = new ConcurrentHashMap<>(); + private final Queue> tasksHolder = new ConcurrentLinkedQueue<>(); private static final DateTimeFormatter TIME_FORMATTER = DateTimeFormatter.ofPattern("HH:mm:ss"); /** - * 添加固定延迟循环任务(无限) + * 添加固定延迟循环任务 * - * @param taskId 任务ID - * @param task 任务 - * @param initialDelay 初始延迟 - * @param delay 延迟 - * @param unit 时间单位 + * @param task 任务 + * @param intervalSeconds 周期(单位秒) */ - public void scheduleFixedDelay(String taskId, Runnable task, long initialDelay, long delay, TimeUnit unit) { - cancelTask(taskId); - ScheduledFuture future = executor.scheduleWithFixedDelay(task, initialDelay, delay, unit); - tasks.put(taskId, future); + public void schedule(Runnable task, long intervalSeconds) { + ScheduledFuture future = executor.scheduleWithFixedDelay(task, 0, intervalSeconds, TimeUnit.SECONDS); + tasksHolder.add(future); } /** * 添加固定次数循环任务 * - * @param taskId 任务ID - * @param task 任务 - * @param initialDelay 初始延迟 - * @param period 周期 - * @param unit 时间单位 - * @param times 执行次数 + * @param task 任务 + * @param intervalSeconds 周期(单位秒) + * @param times 执行次数 */ - public void scheduleFixedTimes(String taskId, Runnable task, long initialDelay, long period, TimeUnit unit, int times) { - cancelTask(taskId); - ScheduledFuture future = executor.scheduleWithFixedDelay(new LimitedTask(task, times), initialDelay, period, unit); - tasks.put(taskId, future); + public void schedule(Runnable task, long intervalSeconds, int times) { + ScheduledFuture future = executor.scheduleWithFixedDelay(new LimitedTask(task, times), 0, intervalSeconds, TimeUnit.SECONDS); + tasksHolder.add(future); } + + private final Map> taskTimeMap = new ConcurrentHashMap<>(); + /** - * 添加多时间点任务(例如 "08:30:00,12:00:00,18:00:00") + * 添加单时间点任务 * - * @param taskId 任务ID - * @param task 任务 - * @param timePoints 时间点字符串(逗号分隔) + * @param task + * @param time */ - public void scheduleAtTimes(String taskId, Runnable task, String timePoints) { - cancelTask(taskId); + public void schedule(Runnable task, String time) { + schedule(task, Arrays.asList(time.split(","))); + } - List times = parseTimePoints(timePoints); - if (times.isEmpty()) return; + /** + * 添加多时间点任务 + *

+ * 例如 "08:30:00" + * + * @param task 任务 + * @param time 时间点 + */ + public void schedule(Runnable task, List time) { + if (time.isEmpty()) { + return; + } - Runnable timeChecker = () -> { - LocalTime now = LocalTime.now(); - for (LocalTime scheduledTime : times) { - if (isSameTime(now, scheduledTime)) { - task.run(); + // 转换为数字集合(秒级精度) + ConcurrentSkipListSet timeSet = new ConcurrentSkipListSet<>(); + Runnable trigger = () -> { + for (String string : time) { + int nowSeconds = LocalTime.now().toSecondOfDay(); + int secondOfDay = LocalTime.parse(string, TIME_FORMATTER).toSecondOfDay(); + if (secondOfDay < nowSeconds) { + continue; } + timeSet.add(secondOfDay); + } + }; + trigger.run(); + // 修正时间计算:计算到下一个凌晨的秒数 + long nowSeconds = LocalTime.now().toSecondOfDay(); + // 剩余秒数到次日凌晨 + long delay = (24 * 3600 - nowSeconds) % (24 * 3600); + + // 使用 scheduleAtFixedRate 保证每日执行 + ScheduledFuture triggerFuture = executor.scheduleAtFixedRate( + trigger, + delay, + 24 * 3600, // 24小时周期 + TimeUnit.SECONDS + ); + tasksHolder.add(triggerFuture); + + // 创建每秒检查的任务 + Runnable checker = () -> { + int now = LocalTime.now().toSecondOfDay(); + Integer nextTime = timeSet.floor(now); + if (nextTime != null) { + task.run(); + timeSet.remove(nextTime); } }; - // 每秒检查一次 - ScheduledFuture future = executor.scheduleAtFixedRate(timeChecker, 0, 1, TimeUnit.SECONDS); - tasks.put(taskId, future); - } - - /** - * 取消所有任务 - */ - public void cancelAllTask() { - for (ScheduledFuture future : tasks.values()) { - future.cancel(false); - } - tasks.clear(); + ScheduledFuture checkerFuture = executor.scheduleAtFixedRate(checker, 0, 1, TimeUnit.SECONDS); + tasksHolder.add(checkerFuture); } /** - * 取消指定任务 - * - * @param taskId 任务ID + * 取消任务 */ - public void cancelTask(String taskId) { - ScheduledFuture future = tasks.remove(taskId); - if (future != null) { + public void cancel() { + for (ScheduledFuture future : tasksHolder) { future.cancel(false); } + tasksHolder.clear(); } /** @@ -130,7 +154,9 @@ public class JScheduler { */ private List parseTimePoints(String timePoints) { List result = new ArrayList<>(); - if (timePoints == null || timePoints.trim().isEmpty()) return result; + if (timePoints == null || timePoints.trim().isEmpty()) { + return result; + } String[] parts = timePoints.split(","); for (String part : parts) { @@ -143,19 +169,6 @@ public class JScheduler { return result; } - /** - * 判断两个时间是否相同(忽略毫秒) - * - * @param t1 时间1 - * @param t2 时间2 - * @return 是否相同 - */ - private boolean isSameTime(LocalTime t1, LocalTime t2) { - return t1.getHour() == t2.getHour() && - t1.getMinute() == t2.getMinute() && - t1.getSecond() == t2.getSecond(); - } - /** * 有限次数任务包装器 */ @@ -175,9 +188,9 @@ public class JScheduler { remainingTimes--; if (remainingTimes == 0) { // 任务执行完毕,取消自己 - for (Map.Entry> entry : tasks.entrySet()) { - if (entry.getValue().isDone()) { - tasks.remove(entry.getKey()); + for (ScheduledFuture future : tasksHolder) { + if (future.isDone()) { + tasksHolder.remove(future); } } } @@ -189,28 +202,27 @@ public class JScheduler { JScheduler scheduler = new JScheduler(); // 1. 无限循环任务(每2秒执行一次) - scheduler.scheduleFixedDelay("task1", - () -> System.out.println("无限任务执行: " + LocalTime.now()), - 0, 2, TimeUnit.SECONDS); - - // 2. 有限次数任务(执行5次,每1秒一次) - scheduler.scheduleFixedTimes("task2", - () -> System.out.println("有限任务执行: " + LocalTime.now()), - 0, 1, TimeUnit.SECONDS, 5); - - // 3. 多时间点任务(每天 08:30:00, 12:00:00, 18:00:00 执行) - scheduler.scheduleAtTimes("task3", +// scheduler.schedule(() -> System.out.println("无限任务执行: " + LocalTime.now()), +// 2); + +// // 2. 有限次数任务(执行5次,每1秒一次) +// scheduler.schedule( +// () -> System.out.println("有限任务执行: " + LocalTime.now()), +// 3, 5); +// +// // 3. 多时间点任务(每天 08:30:00, 12:00:00, 18:00:00 执行) + scheduler.schedule( () -> System.out.println("定时任务执行: " + LocalTime.now()), - "08:30:00,12:00:00,18:00:00"); + "12:58:00,18:00:00"); // 运行一段时间后关闭 try { - Thread.sleep(10_000); + Thread.sleep(60_000); } catch (InterruptedException e) { e.printStackTrace(); } - scheduler.cancelAllTask(); + scheduler.cancel(); scheduler.shutdown(); }