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

Kotlin-Sleep-Funktion von Thread verwenden

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

Kotlin-Sleep-Funktion von TimeUnit verwenden

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.

Kotlin-delay-Funktion verwenden

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.sleep für eine kleine synchrone JVM-Operation, bei der das Blockieren des aktuellen Threads beabsichtigt ist.
  • Verwenden Sie TimeUnit.sleep für dasselbe blockierende Verhalten mit einer lesbaren Einheit.
  • Verwenden Sie delay in 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.