java schedule(task, 500, MILLISECONDS) 说明

如果你使用 scheduler.schedule(this, nextDelay, TimeUnit.MILLISECONDS) 这种方式,一定会等上一个任务执行完成后,再延迟 nextDelay 毫秒才调度下一次任务

关键点

  1. schedule() 是单次调度,每次执行完成后才会安排下一次。

  2. 不会重叠执行,因为 ScheduledExecutorService 默认是单线程的(除非你手动用多线程池)。

  3. 如果任务执行时间超过 nextDelay(如 500ms)

      • 任务完成后,才会计算 nextDelay 并安排下一次。

      • 实际间隔 = 任务执行时间 + nextDelay(例如:任务耗时 600ms,nextDelay=500ms → 实际间隔 1100ms)。

    private void startLoopingExecution() {
        scheduler = Executors.newSingleThreadScheduledExecutor(); // 单线程
    
        Runnable task = new Runnable() {
            @Override
            public void run() {
                long startTime = System.currentTimeMillis();
                System.out.println("任务开始: " + DateTimeUtils.getCurrentTimeSSS());
    
                try {
                    // 模拟任务执行时间(假设有时快有时慢)
                    long mockExecutionTime = Math.random() > 0.5 ? 300 : 800; // 300ms 或 800ms
                    Thread.sleep(mockExecutionTime);
                } catch (Exception e) {
                    e.printStackTrace();
                }
    
                long elapsedTime = System.currentTimeMillis() - startTime;
                System.out.println("任务结束,耗时: " + elapsedTime + "ms");
    
                // 固定 500ms 间隔(但实际间隔 = 本次执行时间 + 500ms)
                long nextDelay = 500;
                scheduler.schedule(this, nextDelay, TimeUnit.MILLISECONDS);
            }
        };
    
        // 首次立即执行
        scheduler.schedule(task, 0, TimeUnit.MILLISECONDS);
    }
    

     

    运行结果示例

     
    任务开始: 14:30:00.000  
    任务结束,耗时: 300ms  (下一次将在 500ms 后执行 → 14:30:00.800)  
    任务开始: 14:30:00.800  
    任务结束,耗时: 800ms  (超过 500ms,但仍会等任务完成,再延迟 500ms → 14:30:02.100)  
    任务开始: 14:30:02.100  
    任务结束,耗时: 300ms  (下一次 500ms 后 → 14:30:02.600)  
    ...  

    结论:即使某次任务执行 800ms(超过 500ms),仍然会 等它执行完,再等 500ms 才执行下一次。


    对比其他调度方式

    调度方式是否严格 500ms 间隔是否可能重叠执行适用场景
    schedule(task, 500, MILLISECONDS) ❌ 不严格(实际间隔 = 任务时间 + 500ms) ❌ 不会重叠 需要避免重叠,允许间隔波动
    scheduleAtFixedRate(task, 0, 500, MILLISECONDS) ✅ 严格(尽量按 500ms 间隔) ✅ 可能重叠 需要固定频率,任务必须短于间隔
    scheduleWithFixedDelay(task, 0, 500, MILLISECONDS) ❌ 不严格(实际间隔 = 任务时间 + 500ms) ❌ 不会重叠 类似手动 schedule(),但更简洁

    如何选择?

    • 如果不允许重叠,且可以接受间隔波动 → 用 schedule()(手动调度)或 scheduleWithFixedDelay()

    • 如果必须严格 500ms 触发(即使任务堆积) → 用 scheduleAtFixedRate()(但要确保任务不会长时间阻塞)。

    • 如果想动态调整间隔(如任务超时后缩短延迟)→ 手动 schedule() 是唯一选择。

    你的场景(交易系统)建议 用手动 schedule(),因为:

    1. 避免重叠执行(防止并发问题)。

    2. 可以监控任务耗时,如果超过 500ms 可以报警或优化。

    3. 更灵活,可以动态调整 nextDelay

posted @ 2025-05-30 15:40  锐洋智能  阅读(70)  评论(0)    收藏  举报