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

ScheduledExecutorService执行顺序不符预期的原因及解决方法

问题原因
  • ScheduledExecutorService基于线程池实现,调用scheduleAtFixedRate()只是把任务提交到线程池的任务队列,不会阻塞当前执行main方法的主线程。
  • 主线程提交任务后会立刻继续执行后续的System.out.println("completed"),而线程池中的任务需要等待线程调度(哪怕延迟设为0,线程切换也存在微小开销),所以主线程的打印语句会先执行。
保证执行顺序的方法

结合你代码里“找到关键字就关闭线程池”的逻辑,提供几种实用方案:

方案1:让主线程等待线程池任务完成

提交任务后,用awaitTermination()让主线程阻塞,直到线程池关闭或者超时:

executor.scheduleAtFixedRate(periodicTask, 0, 5, TimeUnit.SECONDS);
// 最多等待1分钟,可根据文件读取耗时调整时长
executor.awaitTermination(1, TimeUnit.MINUTES);
System.out.println("completed");

注意:只有任务里触发executor.shutdown()后,awaitTermination才会结束阻塞;如果一直没找到关键字,超时后主线程会继续执行打印。

方案2:改用一次性任务并阻塞等待

如果你的需求只是执行一次文件查找(不是真的需要周期性执行),可以用submit()提交任务,再通过Future.get()阻塞主线程直到任务完成:

// 替换原有的scheduleAtFixedRate调用
Future<?> future = executor.submit(periodicTask);
future.get(); // 主线程阻塞,直到任务执行完毕
executor.shutdown();
System.out.println("completed");

这种方式更贴合你“找到关键字就结束”的逻辑,避免不必要的周期性调度。

方案3:把后续逻辑放到任务内部

不想阻塞主线程的话,直接把System.out.println("completed")放到任务的最后执行,确保任务跑完才打印:

Runnable periodicTask = () -> {
    try {
        List<String> lines = Files.readAllLines(new File("E:\\MyFile.log").toPath());
        String key = "FIND ME";
        boolean found = false;
        for (String line : lines) {
            if (line.contains(key)) {
                count++;
                System.out.println("found text ..." + count);
                found = true;
                break;
            }
        }
        if (!found) {
            System.out.println("text not found");
        }
        // 任务执行完成后再打印
        System.out.println("completed");
        if (found) {
            executor.shutdown();
        }
    } catch (IOException e) {
        e.printStackTrace();
    }
};

这种方式由任务线程自己处理后续逻辑,主线程不需要等待。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.02 06:05:26