runBlocking — vad är det, blockerande brygga och hur det fungerar

Författare: IT Sectr Publicerad: 2026-06-22 Lästid: 7 min

runBlocking — är en Coroutine Builder i Kotlin som blockerar den aktuella tråden tills den angivna koroutinen har slutförts. Till skillnad från launch och async är den inte någon suspend-funktion och kan anropas från vanlig (blockerande) kod. Enligt JetBrains dokumentation, 2024, fungerar runBlocking som en brygga mellan den synkrona och asynkrona världen, vilket gör det möjligt att starta koroutiner från main-funktionen och tester.

Huvudpunkter

  • runBlocking — blockerande builder som skapar ett CoroutineScope och väntar på att koroutinen slutförs
  • Trådblockering — runBlocking håller den aktuella tråden tills koroutinen och alla underordnade är helt klara
  • Ingångspunkter — main(), JUnit-tester och överbryggning mellan blockerande och asynkron kod
  • Förbjudet på Android Main-Thread — anrop av runBlocking i UI-tråden orsakar ANR
  • Alternativ — lifecycleScope, viewModelScope, TestCoroutineDispatcher för Android

Vad är runBlocking?

runBlocking — är en Kotlin-funktion som skapar ett nytt CoroutineScope och startar den angivna koroutinen, blockerar den aktuella tråden tills den är helt klar. Till skillnad från alla andra Coroutine Builder är runBlocking inte någon suspend-funktion och kan anropas från vanlig synkron kod. Signaturen för runBlocking accepterar ett CoroutineContext och ett suspend-block och returnerar ett resultat av typ T.

kotlin
public fun <T> runBlocking(
    context: CoroutineContext = EmptyCoroutineContext,
    block: suspend CoroutineScope.() -> T
): T

runBlocking startar en ny händelseloop (event-loop) i den aktuella tråden. När koroutinen anropar en suspend-funktion (t.ex. delay() eller await()), blockerar runBlocking tråden och utför andra schemalagda koroutiner i samma tråd tills den suspenderade återupptas. Detta är kooperativ blockering — tråden är inte overksam utan bearbetar andra koroutiner.

Hur runBlocking fungerar

Den interna mekanismen för runBlocking bygger på en händelseloop: när en suspend-funktion anropas, suspenderar runBlocking exekveringen av det aktuella blocket och startar andra koroutiner från kön. När suspend-funktionen är klar återupptas exekveringen. Denna cykel fortsätter tills alla koroutiner är klara.

Händelseloopen under huven

runBlocking använder sin egen entrådade pool för att utföra koroutiner. Till skillnad från Dispatchers.IO eller Default växlar inte runBlocking trådar — den bearbetar alla koroutiner i den aktuella tråden och växlar mellan deras exekvering. Detta är den enda buildern som garanterar exekvering i samma tråd.

kotlin
fun main() {
    val threadName = Thread.currentThread().getName()
    println("Före runBlocking på $threadName")

    val result = runBlocking {
        println("Inuti runBlocking på ${Thread.currentThread().getName()}")
        delay(500L)
        "Done"
    }

    println("Efter runBlocking: $result")
}

Utdata kommer att visa att alla tre println utförs på en tråd. runBlocking växlar inte tråd, utan organiserar kooperativ multitasking inom en tråd via händelseloopen.

När ska man använda runBlocking

runBlocking är motiverat i tre scenarier: ingångspunkten main() i konsolapplikationer, enhetstestning av suspend-funktioner och överbryggning — anrop av suspend-kod från callback-baserade eller blockerande bibliotek. I Android-produktionskod är användning på huvudtråden strängt förbjuden.

ScenarioTillämpbarhetRisker
main() konsolapplikationJaInga — detta är ingångspunkten, tråden blockerar inte UI
JUnit-testerJaMinimala — tester är per definition synkrona
Android UI-ThreadNejANR, fördröjningar, frysning av gränssnittet
Callback → CoroutineJa, med försiktighetBlockering av trådpoolen vid långvariga operationer

För Android-tester, använd kotlinx-coroutines-test med TestDispatcher istället för runBlocking. Detta ger kontroll över tiden, automatisk återställning och testisolering.

Alternativ till runBlocking

I de flesta scenarier kan och bör runBlocking ersättas med asynkrona alternativ. För Android är dessa viewModelScope, lifecycleScope eller CoroutineScope med rätt dispatcher. För tester — TestCoroutineDispatcher och runTest.

kotlin
    // Dåligt: runBlocking på Android huvudtråd
runBlocking(Dispatchers.Main) {
    val result = networkApi.fetchData()
    textView.setText(result)
}

// Bra: lifecycleScope
lifecycleScope.launch {
    val result = withContext(Dispatchers.IO) { networkApi.fetchData() }
    textView.setText(result)
}

Ersättningen för tester är runTest från kotlinx-coroutines-test. Den skapar ett TestCoroutineScope med virtuell tid, vilket gör det möjligt att testa fördröjningar utan verklig väntan. Detta snabbar upp tester och gör dem deterministiska.

Exempel på användning av runBlocking

Det vanligaste scenariot är testning av suspend-funktioner. runBlocking i tester gör det möjligt att synkront vänta på resultatet av en koroutin utan att ändra arkitekturen. Det andra scenariot är bibliotek med callback-API, där suspend-funktioner anropas från en blockerande kontext via runBlocking.

kotlin
// Testa suspend-funktion med runBlocking
class RepositoryTest {
    @Test
    fun `fetchUser returns correct data`() {
        val repository = UserRepository(FakeApi())

        val result = runBlocking {
            repository.fetchUser("123")
        }

        assertEquals("John", result.name)
        assertEquals("john@test.com", result.email)
    }
}

För överbryggning mellan callback- och suspend-världen, använd CompletableDeferred i kombination med runBlocking istället för callbacks — detta förenklar kedjor av asynkrona operationer och förbättrar kodens läsbarhet.

Risker med felaktig användning

Felaktig användning av runBlocking är ett av de vanliga misstagen vid övergången från blockerande till koroutiner. Huvudproblem: anrop på Android Main-Thread, nästling av runBlocking, användning inuti asynkrona funktioner och start av långvariga operationer via runBlocking.

  • ANR — runBlocking på Android Main-Thread blockerar UI-rendering i mer än 5 sekunder
  • Deadlock — nästlad runBlocking inuti en koroutin på samma tråd leder till ömsesidig blockering
  • Förvirring med dispatchers — Dispatchers.Main inuti runBlocking i en bakgrundstråd har ingen Looper och kraschar med undantag
  • Minnesläckor — runBlocking avbryts inte automatiskt när Activity/Fragment förstörs

Gyllene regeln: runBlocking är en brygga, inte en ersättning. Använd den endast för att koppla samman blockerande och icke-blockerande världar. För alla andra uppgifter, använd launch, async eller lifecycleScope.

Vanliga frågor

Varför blockerar runBlocking tråden medan andra builders inte gör det?

runBlocking är den enda buildern som inte är en suspend-funktion. Den startar en händelseloop i den aktuella tråden och lämnar inte tillbaka kontrollen förrän alla koroutiner har slutförts. launch och async lämnar omedelbart tillbaka kontrollen och utför koroutinen i bakgrunden.

Kan man använda runBlocking i Android ViewModel?

Rekommenderas inte. ViewModel har inbyggd viewModelScope som automatiskt hanterar koroutiner och avbryter dem vid förstöring. runBlocking i ViewModel blockerar tråden och reagerar inte på livscykelavbrott.

Vad ersätter runBlocking i enhetstester?

Använd runTest från biblioteket kotlinx-coroutines-test. Den ger en TestCoroutineScope med virtuell tidskontroll, automatisk avbrytning och deterministisk exekvering.

Vad är event-loop i runBlocking?

Event-loop — händelsebearbetningscykeln inuti runBlocking. När en koroutin suspenderas (t.ex. delay()), växlar händelseloopen till att utföra andra redo koroutiner i samma tråd. Detta skapar illusionen av multitasking utan trådbyte.

Vad händer om runBlocking anropas inuti runBlocking?

Nästlad runBlocking i en enda tråd skapar en deadlock — det yttre blocket väntar på det inre, men det inre kan inte börja förrän det yttre har slutförts. I olika trådar är detta acceptabelt men starkt avrått på grund av svårigheten med felsökning.

Sammanfattning

  • runBlocking — blockerande Coroutine Builder, brygga mellan blockerande och asynkron kod
  • Event-loop runBlocking bearbetar koroutiner kooperativt i en tråd utan växling
  • Tillåtna scenarier — main(), JUnit-tester, överbryggning från callback-bibliotek
  • Förbjudna scenarier — Android UI-Thread, nästlade anrop, långvariga operationer
  • Alternativ — lifecycleScope, viewModelScope, runTest för tester
  • ANR-risk — runBlocking på Main-Thread orsakar frysning av appen efter 5 sekunder
  • Använd asynkrona builders för Android-produktionskod — runBlocking är inte avsett för UI

Vi utvecklar en mobil applikation nyckelfärdigt

IT Sectr skapar iOS- och Android-applikationer för startups och företag sedan 2017. Vi ger dig råd och föreslår den bästa lösningen.

Diskutera projektet

Läs också