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() 還原中斷狀態。較高層的程式碼便能察覺取消要求,並依照應用程式的政策處理。呼叫 sleep 只會暫停目前的執行緒,不會暫停程序中的其他執行緒。
使用 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");
}
}
若短暫暫停目前執行緒正是預期行為,請使用 sleep 方法。若其他工作應繼續執行,或工作必須延後或重複執行,請選擇排程執行器。sleep 會阻塞呼叫端執行緒,且不需要清理執行器;排程工作則讓該執行緒可以繼續處理其他工作,但不再需要執行器時應將它關閉,並取消不再需要的重複工作。