From c779c3fb0b57969318631d71ffa4ef47d4b4f855 Mon Sep 17 00:00:00 2001 From: wangbing Date: Fri, 26 Sep 2025 17:44:43 +0800 Subject: [PATCH] =?UTF-8?q?=E4=B8=8A=E4=BC=A0=E5=A4=87=E4=BB=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/xyz/wbsite/jmacro/JMainService.java | 66 +++--- .../java/xyz/wbsite/jmacro/JScheduler.java | 217 ++++++++++++++++++ .../java/xyz/wbsite/jmacro/util/TaskUtil.java | 9 - 3 files changed, 244 insertions(+), 48 deletions(-) create mode 100644 src/main/java/xyz/wbsite/jmacro/JScheduler.java diff --git a/src/main/java/xyz/wbsite/jmacro/JMainService.java b/src/main/java/xyz/wbsite/jmacro/JMainService.java index 4b9db8a..9706a6a 100644 --- a/src/main/java/xyz/wbsite/jmacro/JMainService.java +++ b/src/main/java/xyz/wbsite/jmacro/JMainService.java @@ -1,11 +1,13 @@ package xyz.wbsite.jmacro; -import cn.hutool.core.thread.ThreadUtil; +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; import java.io.File; +import java.util.List; /** * 服务线程 @@ -36,18 +38,25 @@ public class JMainService { /** * 守护线程 */ - public DaemonThread daemonThread; + public MacroTask macroTask = new MacroTask(); /** * 脚本 */ private JMacro macro; + /** + * 执行次数 + */ + private int count; + /** * 服务内部构造器 */ private JMainService() { Logger.info("初始化服务"); + + } public JMacro getMacro() { @@ -59,15 +68,6 @@ public class JMainService { Legend.setDefaultBase(legendDir); } - public void createDaemon() { - Logger.info("初始化线程"); - this.daemonThread = new DaemonThread(); - this.daemonThread.setDaemon(true); - Logger.info("启动线程"); - this.run = true; - this.daemonThread.start(); - } - public static boolean start() { if (JMainService.getInstance().macro.getWorkRegion() == null) { JMainService.getInstance().macro.startFocus(); @@ -79,8 +79,8 @@ public class JMainService { return false; } - // 创建线程 - JMainService.getInstance().createDaemon(); + // 4. 指定每天固定时间点执行 + List times = CollUtil.newArrayList("08:00", "12:35", "18:10"); return true; } @@ -96,15 +96,14 @@ public class JMainService { JMainService.getInstance().macro.stop(); } // 关闭守护线程 - JMainService.getInstance().daemonThread.interrupt(); - Logger.info("正在停止脚本"); + Logger.info("服务已停止"); return true; } /** * 守护线程 */ - public class DaemonThread extends Thread { + public class MacroTask implements Runnable { @Override public void run() { @@ -113,31 +112,20 @@ public class JMainService { return; } - int intervalValue = JProp.getInstance().getInt("interval", 60); - int timesValue = JProp.getInstance().getInt("times", 3); - int index = 0; - do { - Logger.info("第{}/{}次正在执行", index + 1, timesValue); - try { - macro.start(); - if (index >= timesValue - 1) { - Logger.info("第{}/{}次执行结束", index + 1, timesValue); - } else { - Logger.info("第{}/{}次执行结束,休眠{}秒", index + 1, timesValue, intervalValue); - ThreadUtil.sleep(intervalValue * 1000L); - } - } catch (Exception e) { - if (e.getMessage().contains(InterruptedException.class.getSimpleName())) { - // 服务停止 - } else { - Logger.info("异常中断"); - } + ++count; + + Logger.info("第{}次开始执行>>>>>>", count); + try { + macro.start(); + } catch (Exception e) { + if (e.getMessage().contains(InterruptedException.class.getSimpleName())) { + // 服务停止 + } else { + Logger.info("第{}次中断执行>>>>>>", count); } - index++; - } while (index < timesValue && run); + } - JMainController.getInstance().onStop(); - Logger.info("执行结束,守护线程已退出"); + Logger.info("第{}次执行结束>>>>>>", count); } } } diff --git a/src/main/java/xyz/wbsite/jmacro/JScheduler.java b/src/main/java/xyz/wbsite/jmacro/JScheduler.java new file mode 100644 index 0000000..b7523a9 --- /dev/null +++ b/src/main/java/xyz/wbsite/jmacro/JScheduler.java @@ -0,0 +1,217 @@ +package xyz.wbsite.jmacro; + +import java.time.LocalTime; +import java.time.format.DateTimeFormatter; +import java.util.ArrayList; +import java.util.List; +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; + +/** + * JScheduler: 轻量调度器,基于 ScheduledExecutorService + *

+ * 1. 支持循环执行 + * 2. 支持定时执行 + * + * @author wangbing + * @version 0.0.1 + * @since 1.8 + */ +public class JScheduler { + + /** + * 单线程调度器 + */ + private final ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor(); + + /** + * 任务映射表,用于存储任务ID和对应的 ScheduledFuture 对象 + */ + private final Map> tasks = new ConcurrentHashMap<>(); + + private static final DateTimeFormatter TIME_FORMATTER = DateTimeFormatter.ofPattern("HH:mm:ss"); + + /** + * 添加固定延迟循环任务(无限) + * + * @param taskId 任务ID + * @param task 任务 + * @param initialDelay 初始延迟 + * @param delay 延迟 + * @param unit 时间单位 + */ + 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); + } + + /** + * 添加固定次数循环任务 + * + * @param taskId 任务ID + * @param task 任务 + * @param initialDelay 初始延迟 + * @param period 周期 + * @param unit 时间单位 + * @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); + } + + /** + * 添加多时间点任务(例如 "08:30:00,12:00:00,18:00:00") + * + * @param taskId 任务ID + * @param task 任务 + * @param timePoints 时间点字符串(逗号分隔) + */ + public void scheduleAtTimes(String taskId, Runnable task, String timePoints) { + cancelTask(taskId); + + List times = parseTimePoints(timePoints); + if (times.isEmpty()) return; + + Runnable timeChecker = () -> { + LocalTime now = LocalTime.now(); + for (LocalTime scheduledTime : times) { + if (isSameTime(now, scheduledTime)) { + task.run(); + } + } + }; + + // 每秒检查一次 + 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(); + } + + /** + * 取消指定任务 + * + * @param taskId 任务ID + */ + public void cancelTask(String taskId) { + ScheduledFuture future = tasks.remove(taskId); + if (future != null) { + future.cancel(false); + } + } + + /** + * 关闭调度器 + */ + public void shutdown() { + executor.shutdown(); + } + + /** + * 解析多时间点字符串 + * + * @param timePoints 时间点字符串(逗号分隔) + * @return 解析后的时间列表 + */ + private List parseTimePoints(String timePoints) { + List result = new ArrayList<>(); + if (timePoints == null || timePoints.trim().isEmpty()) return result; + + String[] parts = timePoints.split(","); + for (String part : parts) { + try { + result.add(LocalTime.parse(part.trim(), TIME_FORMATTER)); + } catch (Exception e) { + System.err.println("无效的时间格式: " + part.trim()); + } + } + 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(); + } + + /** + * 有限次数任务包装器 + */ + private class LimitedTask implements Runnable { + private final Runnable task; + private int remainingTimes; + + LimitedTask(Runnable task, int times) { + this.task = task; + this.remainingTimes = times; + } + + @Override + public void run() { + if (remainingTimes > 0) { + task.run(); + remainingTimes--; + if (remainingTimes == 0) { + // 任务执行完毕,取消自己 + for (Map.Entry> entry : tasks.entrySet()) { + if (entry.getValue().isDone()) { + tasks.remove(entry.getKey()); + } + } + } + } + } + } + + public static void main(String[] args) { + 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", + () -> System.out.println("定时任务执行: " + LocalTime.now()), + "08:30:00,12:00:00,18:00:00"); + + // 运行一段时间后关闭 + try { + Thread.sleep(10_000); + } catch (InterruptedException e) { + e.printStackTrace(); + } + + scheduler.cancelAllTask(); + + scheduler.shutdown(); + } +} diff --git a/src/main/java/xyz/wbsite/jmacro/util/TaskUtil.java b/src/main/java/xyz/wbsite/jmacro/util/TaskUtil.java index 10f70c1..003197e 100644 --- a/src/main/java/xyz/wbsite/jmacro/util/TaskUtil.java +++ b/src/main/java/xyz/wbsite/jmacro/util/TaskUtil.java @@ -135,15 +135,6 @@ public class TaskUtil extends CronUtil { return service.scheduleAtFixedRate(runnable, initialDelay, delay, TimeUnit.MILLISECONDS); } - public static void main(String[] args) { - TaskUtil.execTask(new Runnable() { - @Override - public void run() { - System.out.println("1"); - } - }, 3, 3000); - } - /** * 执行指定任务一定次数 *