1. 引言

在Java程序中添加延迟或暂停操作是常见需求,常用于任务节奏控制或等待其他任务完成。本文将介绍两种实现延迟的方法,并分析各自的适用场景。

2. 基于线程的实现方案

Java程序运行时会创建一个宿主机器上的进程,该进程至少包含一个主线程。Java支持多线程编程,允许创建与主线程并行或异步运行的线程。

2.1. 使用 Thread.sleep

最简单粗暴的暂停方式是让当前线程休眠指定时间:

try {
    Thread.sleep(1000); // 暂停1秒
} catch (InterruptedException e) {
    Thread.currentThread().interrupt(); // 恢复中断状态
    e.printStackTrace();
}

最佳实践:务必将sleep包裹在try/catch块中。当其他线程中断休眠线程时,捕获InterruptedException后需显式恢复中断状态,这对后续处理至关重要。单线程程序也建议保留此习惯,避免未来添加线程时踩坑。

2.2. 使用 TimeUnit.sleep

为提升可读性,可用TimeUnit.XXX.sleep(y)语法:

try {
    TimeUnit.SECONDS.sleep(1); // 暂停1秒
} catch (InterruptedException e) {
    Thread.currentThread().interrupt();
    e.printStackTrace();
}

但线程方案存在明显缺陷:

  • 时间精度有限,尤其使用毫秒/纳秒时误差明显
  • 循环中使用时,因代码执行时间累积会导致延迟漂移

3. 基于ExecutorService的实现方案

Java提供的ScheduledExecutorService接口是更健壮精准的解决方案,支持延迟执行或周期性任务。

3.1. 延迟单次执行

使用schedule方法实现延迟执行:

ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor();
executor.schedule(Classname::someTask, delayInSeconds, TimeUnit.SECONDS);

其中Classname::someTask指定要执行的方法:

  • someTask是目标方法名
  • Classname是包含该方法的类名

3.2. 周期性执行

使用scheduleAtFixedRate实现固定间隔执行:

ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor();
executor.scheduleAtFixedRate(Classname::someTask, 0, delayInSeconds, TimeUnit.SECONDS);

此方法会按固定间隔重复调用someTask,有效避免线程方案中的漂移问题,时间控制更精确。

4. 总结

本文对比了Java中实现延迟的两种方案:

  • 线程方案:适合简单场景,但存在精度和漂移问题
  • ExecutorService方案:推荐用于复杂场景,提供更精准的定时控制

根据实际需求选择合适方案,避免在关键业务中踩坑。

最后文中完整代码可在 Github 上找到。


原始标题:How to Delay Code Execution in Java | Baeldung