HOWTO · Java
如何在 Java 中延迟几秒钟的时间
了解何时使用 Thread.sleep() 进行阻塞式暂停,以及何时在 Java 中调度延迟或重复的工作。
本页内容
简单暂停时,调用 Thread.sleep();它会让当前线程暂停指定时长。如果要在稍后执行任务,或在调用线程继续运行时重复执行任务,请使用 ScheduledExecutorService。以下示例展示了这两种方式、如何处理中断,以及如何清理已调度的任务。
暂停执行属于 Java 教程 的实用工具分组,与其他日常的日期、随机数和控制台配方并列。
使用 Thread.sleep() 实现简单的阻塞延迟
Thread.sleep() 接受以毫秒为单位的时长,并暂停调用它的线程。这个独立程序会等待一秒后打印消息。它的 main 方法声明了 InterruptedException,因此发生中断时会将异常传递给调用方,而不是悄悄忽略。
public class Main {
public static void main(String[] args) throws InterruptedException {
Thread.sleep(1000);
System.out.println("One second has passed.");
}
}
如果某个方法无法将 InterruptedException 传递给调用方,就捕获该异常,并调用 Thread.currentThread().interrupt() 恢复中断状态。更高层的代码随后可以检测到取消请求,并按照应用程序的策略作出响应。休眠只会暂停当前线程,不会暂停进程中的其他线程。
使用 TimeUnit.sleep() 明确表示延迟单位
TimeUnit.SECONDS.sleep(2) 可以直接表示暂停两秒。它仍会阻塞调用线程,也可能被中断,因此应采用与 Thread.sleep() 相同的中断处理策略。
import java.util.concurrent.TimeUnit;
public class Main {
public static void main(String[] args) {
try {
TimeUnit.SECONDS.sleep(2);
System.out.println("Two seconds have passed.");
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
System.out.println("Pause interrupted.");
}
}
}
当明确写出时间单位能让时长更容易理解时,可以选择这种写法。TimeUnit.sleep() 是一种清晰表达定时等待的方式,但延迟期间当前线程仍会被阻塞,无法继续处理其他工作。
使用 ScheduledExecutorService 调度重复任务
ScheduledExecutorService 可以在延迟后或按固定间隔运行 Runnable,同时让调用线程继续工作。scheduleAtFixedRate() 接收任务、初始延迟、执行周期和一个 TimeUnit。执行器会调用任务的 run() 方法;run() 中包含要执行的工作,但它本身不会调度任务。
此程序会在一秒后启动任务,并请求此后每隔一秒再运行一次。另一个单独调度的操作会在五秒后取消重复任务并关闭执行器。调度执行取决于运行时的资源情况,因此打印行数和时间可能有所不同。
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
public class Main {
public static void main(String[] args) {
ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor();
ScheduledFuture<?> task = executor.scheduleAtFixedRate(
() -> System.out.println("Task running"), 1, 1, TimeUnit.SECONDS);
executor.schedule(() -> {
task.cancel(false);
executor.shutdown();
}, 5, TimeUnit.SECONDS);
}
}
如果可能需要取消重复任务,请保留返回的 ScheduledFuture。当应用程序不再需要执行器时,应将其关闭;否则,它的工作线程可能会使进程继续运行。如果只需要延迟执行一次任务,请使用 schedule(),而不是重复调度。
在 ScheduledExecutorService 中使用方法引用
如果已有的无参数方法可以充当任务,就可以用方法引用将其作为 Runnable 提供。此程序会在两秒后调度一次方法调用,然后关闭执行器。关闭后不会再提交新任务,但队列中已有的任务仍可完成。
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
public class Main {
public static void main(String[] args) {
ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor();
executor.schedule(Main::executeTask, 2, TimeUnit.SECONDS);
executor.shutdown();
}
private static void executeTask() {
System.out.println("Task running");
}
}
如果短暂暂停时确实需要停止当前线程,请使用休眠方法。如果其他工作应继续进行,或者任务需要稍后执行或重复执行,请选择调度执行器。休眠会阻塞调用线程,无需清理执行器;调度任务可以让该线程继续工作,但不再需要时应关闭执行器并取消重复任务。