1. 概述

Java 程序中经常需要延迟或暂停当前操作来控制速度,或等待另一个任务完成。

本文我们将介绍 2 种方式来实现延时执行任务。

2. 基于 Thread 方法

When a Java program runs, it spawns a process that runs on the host machine. This process contains at least one thread – the main thread – in which the program runs. Furthermore, Java enables multithreading, which enables applications to create new threads that run in parallel, or asynchronously, to the main thread.

2.1. 使用 Thread.sleep

一种快速但粗暴的方式是使用 Thread.sleep(milliseconds) 让当前线程休眠一段时间:

try {
    Thread.sleep(secondsToSleep * 1000);
} catch (InterruptedException ie) {
    Thread.currentThread().interrupt();
}

It is good practice to wrap the sleep method in a try/catch block in case another thread interrupts the sleeping thread. In this case, we catch the InterruptedException and explicitly interrupt the current thread, so it can be caught later and handled. This is more important in a multi-threaded program, but still good practice in a single-threaded program in case we add other threads later.

2.2. 使用 TimeUnit.sleep

为了更好的可读性,我们可以改用 TimeUnit.XXX.sleep(y),其中XXX 表示时间单位(SECONDS*, MINUTES等) ,y 是需要休眠的时间值。 其背后还是使用的 Thread.sleep,下面是它的用法:

try {
    TimeUnit.SECONDS.sleep(secondsToSleep);
} catch (InterruptedException ie) {
    Thread.currentThread().interrupt();
}

但, 使用基于线程方式有几个缺点

  • sleep 时间不精确,特别是当时间增量较小时,如毫秒、纳秒。
  • 在循环内部使用时,sleep会因其他代码执行而在循环迭代之间略微漂移,因此在多次迭代后执行时间可能变得不精确

3. 基于 ExecutorService 方法

Java 提供了更健壮、更精确的解决方案 —— ScheduledExecutorService 接口。该接口可以安排代码在指定的延迟或固定的时间间隔后运行一次。

要延迟运行一段代码,我们可以使用 schedule 方法:

ScheduledExecutorService executorService = Executors.newSingleThreadScheduledExecutor();

executorService.schedule(Classname::someTask, delayInSeconds, TimeUnit.SECONDS);

Classname::someTask 指定了我们要延迟执行的方法:

  • someTask 是我们要执行的方法名
  • Classname 是包含 someTask 类名

以固定时间间隔执行,可以使用 scheduleAtFixedRate

ScheduledExecutorService executorService = Executors.newSingleThreadScheduledExecutor();

executorService.scheduleAtFixedRate(Classname::someTask, 0, delayInSeconds, TimeUnit.SECONDS);

这会重复调用 someTask 方法,每次调用之间暂停 delayInSeconds 秒。

除了允许更多的计时选项之外,ScheduledExecutorService方法还可以产生更精确的时间间隔,因为它可以防止漂移问题。

4. 总结

In this article, we discussed two methods for creating delays in Java programs.

The full code for this article can be found over on Github. This is a Maven-based project, so it should be easy to import and run as it is.