HOWTO · Kotlin
Thread-Ausführung in Kotlin mit Sleep anhalten
Erfahren Sie, wie Sie Kotlin/JVM-Threads mit Thread.sleep oder TimeUnit pausieren und wann delay oder ScheduledExecutorService geeigneter sind.
Auf dieser Seite
Verwenden Sie Thread.sleep, wenn synchroner Kotlin/JVM-Code den aktuellen Thread pausieren muss. Verwenden Sie TimeUnit.sleep, wenn eine benannte Zeiteinheit die Verzögerung verständlicher macht. In Coroutinen verwenden Sie delay, damit die Coroutine ihren Thread nicht blockiert; für eine Aufgabe, die später ausgeführt werden soll, verwenden Sie stattdessen ScheduledExecutorService. Jeder schlafende Thread kann unterbrochen werden, und eine Verzögerung ist eine Mindestwartezeit, keine exakt garantierte Ausführungszeit.
Coroutine ist die technische Bezeichnung für eine nicht blockierende Ausführungseinheit; coroutine ist die englische Bezeichnung.
Mit Thread.sleep den aktuellen Thread blockieren
Thread.sleep(milliseconds) ist die direkte JVM-Operation, um den aufrufenden Thread zu pausieren. Das Argument ist eine Long-Anzahl von Millisekunden, und die Methode löst InterruptedException aus. Produktionscode sollte das Interrupt-Flag wiederherstellen oder die Unterbrechung weitergeben, statt nur einen Stacktrace auszugeben.
fun main() {
println("before")
try {
Thread.sleep(100L)
println("after")
} catch (exception: InterruptedException) {
Thread.currentThread().interrupt()
println("interrupted")
}
}
Ausgabe:
before
after
Der aufrufende Thread wird mindestens ungefähr 100 Millisekunden blockiert. Die gesamte JVM wird dadurch nicht angehalten: Andere bereite Threads können weiterlaufen. Vermeiden Sie dies in einer Event-Schleife oder auf einem begrenzten Worker-Thread, wenn sich die Arbeit als nicht blockierende Suspension ausdrücken lässt.
Mit TimeUnit.sleep lesbare Einheiten verwenden
TimeUnit aus java.util.concurrent konvertiert eine benannte Einheit wie Sekunden oder Millisekunden vor dem Schlafen. Es blockiert weiterhin den aktuellen Thread und reagiert weiterhin auf Unterbrechungen, aber TimeUnit.SECONDS.sleep(1) ist leichter zu prüfen als eine literale Millisekundenumrechnung.
import java.util.concurrent.TimeUnit
fun main() {
println("before")
try {
TimeUnit.MILLISECONDS.sleep(100)
println("after")
} catch (exception: InterruptedException) {
Thread.currentThread().interrupt()
println("interrupted")
}
}
Ausgabe:
before
after
Wählen Sie die Einheit passend zur Anforderung. Die Umrechnung garantiert kein exaktes Timing: Wegen Scheduling, Konkurrenz oder der Auflösung des Betriebssystem-Timers kann der Thread später fortgesetzt werden.
In einer Coroutine delay verwenden
delay ist eine suspendierende Funktion aus kotlinx-coroutines-core. Sie pausiert die Coroutine, ohne den zugrunde liegenden Thread zu blockieren, sodass eine andere Coroutine diesen Thread verwenden kann. Sie muss aus einer suspendierenden Funktion oder einem Coroutine-Scope aufgerufen werden und ersetzt Thread.sleep nicht in gewöhnlichem synchronem Code.
Ein runBlocking-Scope kann beispielsweise eine Coroutine starten, die delay(100L) aufruft und danach eine Nachricht ausgibt. Die Reihenfolge dieser Nachricht hängt vom Scheduling ab; außerdem ist Abbruch eine wichtige Grenze: delay ist abbrechbar, daher endet eine abgebrochene Coroutine normalerweise am Suspension-Punkt. Fügen Sie vor dem Kompilieren von Coroutine-Code die Abhängigkeit kotlinx-coroutines-core hinzu; die Kotlin-Standardbibliothek stellt delay allein nicht bereit.
Arbeit mit ScheduledExecutorService planen
Verwenden Sie ScheduledExecutorService, wenn die Anforderung „diese Aufgabe später ausführen“ lautet und nicht „diesen aktuellen Thread schlafen lassen“. Eine geplante Aufgabe kann vor ihrer Ausführung abgebrochen werden, und der Executor sollte nach seiner Verwendung beendet werden.
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()
}
Ausgabe:
task ran
get() hält dieses kurze Kommandozeilenbeispiel nur so lange am Leben, bis die Aufgabe abgeschlossen ist. In einer Anwendung behalten Sie das zurückgegebene ScheduledFuture, wenn Sie die Aufgabe abbrechen müssen, und verwenden shutdown oder shutdownNow gemäß der Lebenszyklusstrategie der Anwendung. Scheduling ist keine präzise Echtzeitgarantie.
Welche Kotlin-Sleep-Methode sollten Sie wählen?
- Verwenden Sie
Thread.sleepfür eine kleine synchrone JVM-Operation, bei der das Blockieren des aktuellen Threads beabsichtigt ist. - Verwenden Sie
TimeUnit.sleepfür dasselbe blockierende Verhalten mit einer lesbaren Einheit. - Verwenden Sie
delayin Coroutinen für eine abbrechbare, nicht blockierende Suspension. - Verwenden Sie
ScheduledExecutorService, wenn nach einer Verzögerung eine separate Aufgabe ausgelöst werden soll.
Verwenden Sie wait() nicht als allgemeine Sleep-Operation. Object.wait() aus Java ist Teil der Monitor-Koordination und erfordert den passenden Monitor; es löst ein anderes Synchronisationsproblem. Behandeln Sie Unterbrechung und Abbruch unabhängig von der gewählten API als normalen Kontrollfluss und nicht als unerwartete Fehler.