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

循环迭代前的非阻塞延迟失效问题求助

我明白你现在的困扰——想用非阻塞的方式在循环每次迭代前等一会儿,结果用Timer的时候所有任务一下子都启动了,完全没达到预期的延迟效果对吧?

先说说你遇到的核心问题

在for循环里创建Timer并调度任务时,循环会在极短时间内跑完所有迭代,把所有Timer任务一股脑塞进调度队列。如果你的延迟时间是固定值(比如每次等3秒),这些任务会几乎同时触发——因为循环执行的时间远小于你的延迟时间,所以看起来所有myProcessfor20Seconds()都要等循环结束后才会开始执行,完全没实现“每次迭代前等待”的逻辑。

而且Timer本身也有局限性:它是单线程的,一旦某个任务抛出未捕获的异常,整个Timer都会停止工作,可靠性不如Java并发包提供的工具。

给你两个靠谱的解决方案

方案1:顺序执行(等待→执行→等待→执行,非阻塞)

如果你希望每次必须等前一个myProcessfor20Seconds()执行完,再等待一段时间启动下一个,用ScheduledExecutorService配合递归调度是最好的选择,全程不会阻塞主线程:

import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;

public class DelayedProcessDemo {
    // 自定义参数:循环总次数、每次迭代前等待的秒数
    private static final int TOTAL_LOOPS = 5;
    private static final long WAIT_BEFORE_ITERATION = 3;
    
    // 单线程调度器,保证任务顺序执行
    private static final ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor();
    private static final AtomicInteger loopCounter = new AtomicInteger(0);

    public static void main(String[] args) {
        // 启动第一个任务
        scheduleNextProcess();
        
        // 这里可以放心执行其他代码,不会被阻塞
        System.out.println("主线程继续处理其他任务...");
    }

    private static void scheduleNextProcess() {
        int currentLoop = loopCounter.getAndIncrement();
        if (currentLoop >= TOTAL_LOOPS) {
            scheduler.shutdown(); // 所有任务完成后关闭调度器,避免内存泄漏
            return;
        }

        // 先等待指定时间,再执行耗时任务;任务完成后自动调度下一次
        scheduler.schedule(() -> {
            try {
                myProcessfor20Seconds(currentLoop);
            } finally {
                scheduleNextProcess();
            }
        }, WAIT_BEFORE_ITERATION, TimeUnit.SECONDS);
    }

    private static void myProcessfor20Seconds(int loopNum) {
        System.out.println("开始执行第" + (loopNum + 1) + "次耗时任务");
        try {
            Thread.sleep(20000); // 模拟20秒的耗时操作
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            System.err.println("第" + (loopNum + 1) + "次任务被中断");
        }
        System.out.println("第" + (loopNum + 1) + "次耗时任务执行完成");
    }
}

这个方案的优势:

  • 用AtomicInteger做线程安全的计数,避免多线程下的计数错误
  • 单线程调度器保证任务按顺序执行,不会同时运行多个myProcessfor20Seconds()
  • 全程非阻塞,主线程可以正常处理其他逻辑

方案2:并行执行(固定间隔启动任务,不管前一个是否完成)

如果你允许同时运行多个myProcessfor20Seconds(),只是希望每次启动任务前间隔固定时间,那可以直接在循环里给每个任务设置递增的延迟:

import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

public class ParallelDelayedProcessDemo {
    private static final int TOTAL_LOOPS = 5;
    private static final long INTERVAL = 3;

    public static void main(String[] args) {
        // 根据需求调整线程池大小,避免同时运行太多任务导致资源耗尽
        ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(3);

        for (int i = 0; i < TOTAL_LOOPS; i++) {
            int loopNum = i;
            // 第1次等3秒,第2次等6秒...以此类推,实现固定间隔启动
            scheduler.schedule(() -> {
                myProcessfor20Seconds(loopNum);
            }, INTERVAL * (i + 1), TimeUnit.SECONDS);
        }

        // 主线程继续执行其他操作
        System.out.println("主线程继续处理其他任务...");
    }

    private static void myProcessfor20Seconds(int loopNum) {
        System.out.println("并行启动第" + (loopNum + 1) + "次耗时任务");
        try {
            Thread.sleep(20000);
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            System.err.println("第" + (loopNum + 1) + "次并行任务被中断");
        }
        System.out.println("第" + (loopNum + 1) + "次并行任务执行完成");
    }
}

最后提醒

如果是在Android环境下使用,记得不要在主线程中执行myProcessfor20Seconds()(上面的方案已经用调度器放在后台线程了,没问题),另外在页面销毁或任务不再需要时,一定要调用scheduler.shutdown()或scheduler.shutdownNow(),避免内存泄漏。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.04 18:55:15