Kotlin Academy · leksjon

Rydde opp med finally og NonCancellable

Frigjør ressurser i kansellerte coroutines med finally og withContext(NonCancellable).

Leksjon 3 av 413 trinn

Rydde opp med finally og NonCancellable er en gratis leksjon i Kotlin Academy på CoddyKit. Dette er leksjon 3 av 4. Du kan lese valgfritt 3 leksjoner fra denne læringsstien gratis i sin helhet – deretter låser CoddyKit PRO opp alle leksjoner, samt praktisk øving med en innebygd kodeeditor og en AI-veileder som er tilgjengelig døgnet rundt. Den er en del av læringsløpet i Kotlin Academy, og fremdriften din synkroniseres mellom nettet og CoddyKit-appen. Kurset i Kotlin Academy inneholder totalt 4 leksjoner.

Kansellering og finally

Når en korutine kanselleres, kaster suspensjonspunkter CancellationException. Kode i finally-blokker kjører alltid – men selve finally-blokken kjører i en allerede kansellert korutinekontekst.

import kotlinx.coroutines.*
fun main() = runBlocking {
    val job = launch {
        try {
            delay(1000)
        } finally {
            println("finally: cleaning up")
        }
    }
    delay(50)
    job.cancel()
    job.join()
}

Problem: Suspensjon i finally

Hvis du prøver å bruke delay eller utføre en annen suspensjon i finally for en kansellert korutine, kastes et unntak umiddelbart fordi konteksten allerede er kansellert.

import kotlinx.coroutines.*
fun main() = runBlocking {
    val job = launch {
        try {
            delay(1000)
        } finally {
            // delay(100) // throws CancellationException here!
            println("Sync cleanup OK; async cleanup needs NonCancellable")
        }
    }
    delay(50); job.cancel(); job.join()
}

withContext(NonCancellable)

Pakk suspensjonskall i finally inn i withContext(NonCancellable) for å kjøre dem i en kontekst som ikke kan kanselleres, selv etter at forelderen er kansellert.

import kotlinx.coroutines.*
fun main() = runBlocking {
    val job = launch {
        try {
            delay(1000)
        } finally {
            withContext(NonCancellable) {
                delay(100)  // OK: runs despite cancellation
                println("Async cleanup complete")
            }
        }
    }
    delay(50); job.cancel(); job.join()
}

Når du bør bruke NonCancellable

Bruk NonCancellable til å lukke databasetilkoblinger, tømme logger, sende analysehendelser eller utføre annen asynkron opprydding som må fullføres uansett kansellering.

import kotlinx.coroutines.*
suspend fun closeConnection() {
    println("Closing DB connection...")
    delay(50) // simulate async close
    println("Connection closed")
}
fun main() = runBlocking {
    val job = launch {
        try { delay(1000) }
        finally { withContext(NonCancellable) { closeConnection() } }
    }
    delay(50); job.cancel(); job.join()
}

NonCancellable er ikke et scope

NonCancellable er en Job som du kan sende til withContext. Ikke bruk den direkte som et korutine-scope – bruk den bare til opprydding i finally.

import kotlinx.coroutines.*
fun main() = runBlocking {
    // WRONG usage:
    // launch(NonCancellable) { ... } // launches a coroutine that cannot be cancelled
    // RIGHT usage:
    launch {
        try { delay(500) }
        finally {
            withContext(NonCancellable) {
                println("Safe cleanup")
            }
        }
    }.also { delay(50); it.cancel(); it.join() }
}

Opprydding av flere ressurser

Kjed sammen flere oppryddingsoperasjoner i én enkelt withContext(NonCancellable)-blokk.

import kotlinx.coroutines.*
fun main() = runBlocking {
    launch {
        try {
            delay(1000)
        } finally {
            withContext(NonCancellable) {
                delay(20); println("Step 1: flush cache")
                delay(20); println("Step 2: close socket")
                delay(20); println("Step 3: log audit")
            }
        }
    }.also { delay(50); it.cancel(); it.join() }
}

try/catch/finally-mønsteret

Kombiner try-catch for forretningsfeil med finally for opprydding – dette er det standardiserte strukturerte mønsteret.

import kotlinx.coroutines.*
fun main() = runBlocking {
    launch {
        try {
            delay(100)
            throw RuntimeException("business error")
        } catch (e: RuntimeException) {
            println("Handling: ${e.message}")
        } finally {
            withContext(NonCancellable) {
                println("Always cleanup")
            }
        }
    }.join()
}

Rekkefølge for opprydding

Finally-blokker kjører i motsatt rekkefølge av nøstingen. Den ytre try-finally-blokken kjører etter de indre, akkurat som i vanlig Java/Kotlin-kode.

import kotlinx.coroutines.*
fun main() = runBlocking {
    launch {
        try {
            try {
                delay(1000)
            } finally { println("Inner cleanup") }
        } finally { println("Outer cleanup") }
    }.also { delay(50); it.cancel(); it.join() }
}

use() for AutoCloseable-ressurser

For AutoCloseable-ressurser bruker du Kotlin-utvidelsen use { }, som kaller close() automatisk, også ved unntak eller kansellering.

import kotlinx.coroutines.*
class Connection : AutoCloseable {
    init { println("Opened") }
    override fun close() { println("Closed") }
    suspend fun query(): String { delay(50); return "result" }
}
fun main() = runBlocking {
    val result = Connection().use { it.query() }
    println(result)
}

Logge årsaken til kansellering

Hent kanselleringsmeldingen fra CancellationException i catch eller finally for å logge hvorfor en korutine stoppet.

import kotlinx.coroutines.*
fun main() = runBlocking {
    val job = launch {
        try {
            delay(1000)
        } catch (e: CancellationException) {
            println("Cancelled: ${e.message}")
            throw e
        }
    }
    delay(50)
    job.cancel("user navigated away")
    job.join()
}

Opprydding av CoroutineScope med invokeOnCompletion

Job.invokeOnCompletion registrerer en callback som kjører når jobben avsluttes, uansett årsak – et alternativ til finally for opprydding på foreldrenivå.

import kotlinx.coroutines.*
fun main() = runBlocking {
    val job = launch {
        delay(1000)
    }
    job.invokeOnCompletion { cause ->
        if (cause != null) println("Ended with: ${cause::class.simpleName}")
        else println("Completed normally")
    }
    delay(50)
    job.cancel()
    job.join()
}

Kort kontroll

Hva er formålet med withContext(NonCancellable) i en finally-blokk?

Oppsummering

finally kjører alltid ved kansellering. Pakk suspensjonskall i finally inn i withContext(NonCancellable) slik at de fullføres til tross for kanselleringen. Bruk use { } for AutoCloseable-ressurser.

Gratis å komme i gang

Lær deg Kotlin med en AI-veileder – gratis

Skriv og kjør ekte kode i nettleseren, få umiddelbar hjelp fra en AI-veileder som er tilgjengelig døgnet rundt, og fortsett der du slapp – på nettet eller i appen.

Kurs
51
Leksjoner
203

Ofte stilte spørsmål

Er leksjonen «Rydde opp med finally og NonCancellable» gratis?

Ja – du kan lese valgfritt 3 av leksjonene i læringsstien Kotlin Academy, inkludert «Rydde opp med finally og NonCancellable», gratis i sin helhet her på nettet. Deretter låser CoddyKit PRO opp alle leksjoner, samt interaktiv øving med en innebygd kodeeditor og en AI-veileder som er tilgjengelig døgnet rundt. Kurset i Kotlin Academy inneholder totalt 4 leksjoner.

Hva lærer jeg i «Rydde opp med finally og NonCancellable»?

Frigjør ressurser i kansellerte coroutines med finally og withContext(NonCancellable). Du øver på Kotlin Academy med praktisk kode som du kjører direkte i nettleseren, mens en AI-veileder som er tilgjengelig døgnet rundt, svarer på spørsmålene dine mens du jobber deg gjennom leksjonen.

Trenger jeg erfaring for å begynne med Kotlin Academy?

Ingen tidligere erfaring er nødvendig. Kotlin Academy på CoddyKit er lagt opp for både nybegynnere og viderekomne, så De kan begynne her eller helt fra start og lære i Deres eget tempo. Dette er leksjon 3 av 4.

Hvor lang tid tar leksjonen «Rydde opp med finally og NonCancellable»?

De fleste CoddyKit-leksjoner tar omtrent 5–10 minutter. Hver leksjon er kort og interaktiv, slik at De gjør jevne fremskritt og kan fortsette akkurat der De slapp – både på nettet og i appen.

Kan jeg skrive og kjøre kode i denne Kotlin Academy-leksjonen?

Ja. Alle Kotlin Academy-leksjoner har en innebygd kodeeditor, slik at De kan skrive og kjøre ekte kode direkte i nettleseren og få umiddelbar tilbakemelding fra AI – uten lokal konfigurering.

Alle leksjonene i dette kurset

  1. Kooperativ kansellering: isActive og ensureActive
  2. withTimeout og withTimeoutOrNull
  3. Rydde opp med finally og NonCancellable
  4. Kanselleringsforplantning i coroutine-hierarkier
← Tilbake til Kotlin Academy