HOWTO · Kotlin
在 Kotlin 中使用 Sleep 暫停執行緒執行
了解如何使用 Thread.sleep 或 TimeUnit 暫停 Kotlin/JVM 執行緒,以及何時改用 delay 或 ScheduledExecutorService。
本頁內容
同步 Kotlin/JVM 程式碼需要暫停目前執行緒時,請使用 Thread.sleep。需要以名稱清楚表示時間單位時,請使用 TimeUnit.sleep。在協程中使用 delay,即可暫停協程而不阻塞執行緒;如果工作應稍後執行,請改用 ScheduledExecutorService。任何休眠中的執行緒都可能被中斷,而延遲只是最短等待時間,並非精確的執行時間。
coroutine 是表示非阻塞執行單位的技術術語。
使用 Thread.sleep 阻塞目前執行緒
Thread.sleep(milliseconds) 是暫停呼叫執行緒的直接 JVM 操作。參數是代表毫秒數的 Long,方法會拋出 InterruptedException。正式程式碼應恢復中斷旗標或傳遞中斷,而不是只列印堆疊追蹤。
fun main() {
println("before")
try {
Thread.sleep(100L)
println("after")
} catch (exception: InterruptedException) {
Thread.currentThread().interrupt()
println("interrupted")
}
}
輸出:
before
after
這會讓呼叫執行緒至少阻塞約 100 毫秒,但不會停止整個 JVM,其他可執行的執行緒仍可繼續執行。若工作可以表示為非阻塞的暫停,請避免在事件迴圈或資源有限的工作執行緒中使用它。
使用 TimeUnit.sleep 表示易讀的單位
java.util.concurrent 中的 TimeUnit 會在休眠前轉換秒或毫秒等具名單位。它仍會阻塞目前執行緒並回應中斷,但 TimeUnit.SECONDS.sleep(1) 比直接進行毫秒換算更容易檢閱。
import java.util.concurrent.TimeUnit
fun main() {
println("before")
try {
TimeUnit.MILLISECONDS.sleep(100)
println("after")
} catch (exception: InterruptedException) {
Thread.currentThread().interrupt()
println("interrupted")
}
}
輸出:
before
after
請選擇符合需求的單位。由於排程、競爭或作業系統計時器精度的影響,執行緒可能較晚恢復,因此轉換不保證精確時間。
在協程中使用 delay
delay 是 kotlinx-coroutines-core 提供的暫停函式。它會暫停協程而不阻塞底層執行緒,讓其他協程可以使用該執行緒。它必須從暫停函式或協程作用域呼叫,不是一般同步程式碼中 Thread.sleep 的替代品。
例如,runBlocking 作用域可以啟動呼叫 delay(100L) 後列印訊息的協程。訊息順序取決於排程;取消也是重要邊界,因為 delay 可取消,被取消的協程通常會在暫停點停止。編譯協程程式碼前請加入 kotlinx-coroutines-core 相依性,Kotlin 標準函式庫本身不提供 delay。
使用 ScheduledExecutorService 排程工作
當需求是「稍後執行此工作」而非「讓目前執行緒休眠」時,請使用 ScheduledExecutorService。排程工作可以在執行前取消,Executor 不再需要時應關閉。
import java.util.concurrent.Executors
import java.util.concurrent.TimeUnit
fun main() {
val executor = Executors.newSingleThreadScheduledExecutor()
val task = executor.schedule(
{ println("task ran") },
100,
TimeUnit.MILLISECONDS,
)
task.get()
executor.shutdown()
}
輸出:
task ran
這裡的 get() 只是讓簡短的命令列範例保持執行,直到工作完成。在應用程式中,需要取消工作時請保留傳回的 ScheduledFuture,並依照生命週期策略使用 shutdown 或 shutdownNow。排程不是精確的即時保證。
應該選擇哪種 Kotlin Sleep 方法?
- 目前執行緒應有意阻塞的小型同步 JVM 操作使用
Thread.sleep。 - 需要以易讀單位表達相同阻塞行為時使用
TimeUnit.sleep。 - 協程中的可取消、非阻塞暫停使用
delay。 - 延遲後需要觸發獨立工作時使用
ScheduledExecutorService。
不要將 wait() 當作一般休眠操作。Java 的 Object.wait() 參與監視器協調並要求適當的監視器,它解決的是不同的同步問題。無論選擇哪個 API,都應將中斷與取消視為正常控制流程,而非意外錯誤。