You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Java如何实现由fire方法触发首次执行的固定间隔定时任务调度方法

方案可行性结论

你提出的用列表存储调度任务、fire方法触发执行后更新下次调度时间的思路完全可行,只需调整少量细节即可满足需求,不需要执行完就把任务移出列表再重新添加,直接更新任务的下次触发时间即可,效率更高。

核心实现逻辑

任务存储结构

每个调度任务需要包装三个核心属性:

  • 执行间隔时间
  • 待执行的Runnable任务
  • 下次触发的时间阈值(初始状态设为null,代表还未首次触发)

方法实现逻辑

scheduleEvery 方法

调用时将传入的间隔时间和Runnable包装成任务对象,存入线程安全的任务列表,同时返回ScheduledTask实例用于后续任务取消操作。

fire 方法

传入当前时间戳后遍历任务列表,对每个任务做如下判断:

  • 如果任务已经被标记为取消,直接从列表移除
  • 如果是首次触发(下次触发时间为null),判断当前时间是否大于等于任务的初始触发阈值,满足就执行任务
  • 如果已经触发过,判断当前时间是否大于等于上次设置的下次触发时间,满足就执行任务
  • 任务执行完成后,将下次触发时间更新为当前时间 + 执行间隔
注意事项
  • 线程安全:如果scheduleEvery和fire会被多线程调用,需要使用线程安全的列表实现比如CopyOnWriteArrayList,或者操作列表时加锁,避免并发修改异常
  • 异常处理:任务执行需要包裹try-catch,避免单个任务抛出异常导致整个fire流程中断,其余任务无法正常调度
  • 取消逻辑:返回的ScheduledTask可以实现cancel方法,标记任务为取消状态,下次fire时自动清理
核心代码示例
// 自定义ScheduledTask接口
public interface ScheduledTask {
    void cancel();
}

// 调度器实现
public class PassiveScheduler {
    // 任务包装类
    private static class TaskHolder {
        final long interval;
        final Runnable task;
        Long nextFireTime;
        boolean isCanceled;

        TaskHolder(long interval, Runnable task) {
            this.interval = interval;
            this.task = task;
            this.nextFireTime = null;
            this.isCanceled = false;
        }
    }

    private final List<TaskHolder> taskList = new CopyOnWriteArrayList<>();
    // 初始触发阈值,对应你示例中的time=2001
    private final long initTriggerThreshold;

    public PassiveScheduler(long initTriggerThreshold) {
        this.initTriggerThreshold = initTriggerThreshold;
    }

    public ScheduledTask scheduleEvery(long time, Runnable task) {
        TaskHolder holder = new TaskHolder(time, task);
        taskList.add(holder);
        return () -> holder.isCanceled = true;
    }

    public void fire(long currentTime) {
        for (TaskHolder holder : taskList) {
            if (holder.isCanceled) {
                taskList.remove(holder);
                continue;
            }
            boolean needRun = false;
            if (holder.nextFireTime == null) {
                needRun = currentTime >= initTriggerThreshold;
            } else {
                needRun = currentTime >= holder.nextFireTime;
            }
            if (needRun) {
                try {
                    holder.task.run();
                } catch (Exception e) {
                    // 可自行替换为日志打印
                    e.printStackTrace();
                }
                holder.nextFireTime = currentTime + holder.interval;
            }
        }
    }
}

以上实现完全匹配你给出的运行规则示例。

内容的提问来源于stack exchange,提问作者Celine

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.27 23:45:02