runBlocking — wat is het, blokkerende brug en hoe werkt het

Auteur: IT Sectr Gepubliceerd: 2026-06-22 Leestijd: 7 min

runBlocking is een Coroutine Builder in Kotlin die de huidige thread blokkeert tot de voltooiing van de doorgegeven coroutine. In tegenstelling tot launch en async is het geen suspend-functie en kan het worden aangeroepen vanuit gewone (blokkerende) code. Volgens documentatie van JetBrains, 2024, dient runBlocking als brug tussen de synchrone en asynchrone wereld, waardoor coroutines kunnen worden gestart vanuit de main-functie en tests.

Belangrijkste punten

  • runBlocking — blokkerende builder die een CoroutineScope creëert en wacht op voltooiing van de coroutine
  • Thread blokkering — runBlocking houdt de huidige thread vast tot volledige voltooiing van de coroutine en alle onderliggende
  • Ingangspunten — main(), JUnit-tests en bridging tussen blokkerende en async code
  • Verboden op Android Main-Thread — aanroep van runBlocking in de UI-thread veroorzaakt ANR
  • Alternatieven — lifecycleScope, viewModelScope, TestCoroutineDispatcher voor Android

Wat is runBlocking?

runBlocking is een Kotlin-functie die een nieuwe CoroutineScope creëert en de doorgegeven coroutine start, waarbij de huidige thread wordt geblokkeerd tot de volledige voltooiing ervan. In tegenstelling tot alle andere Coroutine Builders is runBlocking geen suspend-functie en kan het worden aangeroepen vanuit gewone synchrone code. De handtekening van runBlocking accepteert een CoroutineContext en een suspend-blok en retourneert een resultaat van het type T.

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

runBlocking start een nieuwe event-loop in de huidige thread. Wanneer een coroutine een suspend-functie aanroept (bijv. delay() of await()), blokkeert runBlocking de thread en voert andere geplande coroutines in dezelfde thread uit tot de geschorste wordt hervat. Dit is coöperatieve blokkering — de thread staat niet stil, maar verwerkt andere coroutines.

Hoe runBlocking werkt

Het interne mechanisme van runBlocking is gebaseerd op een event-loop: bij aanroep van een suspend-functie onderbreekt runBlocking de uitvoering van het huidige blok en start andere coroutines uit de wachtrij. Wanneer de suspend-functie is voltooid, wordt de uitvoering hervat. Deze cyclus gaat door totdat alle coroutines zijn voltooid.

Event-loop onder de motorkap

runBlocking gebruikt zijn eigen éénthreadige pool voor het uitvoeren van coroutines. In tegenstelling tot Dispatchers.IO of Default schakelt runBlocking geen threads — het verwerkt alle coroutines in de huidige thread, waarbij hun uitvoering wordt afgewisseld. Dit is de enige builder die uitvoering in dezelfde thread garandeert.

kotlin
fun main() {
    val threadName = Thread.currentThread().getName()
    println("Voor runBlocking op $threadName")

    val result = runBlocking {
        println("Binnen runBlocking op ${Thread.currentThread().getName()}")
        delay(500L)
        "Done"
    }

    println("Na runBlocking: $result")
}

De uitvoer zal laten zien dat alle drie println op één thread worden uitgevoerd. runBlocking schakelt geen thread, maar organiseert coöperatieve multitasking binnen één thread via een event-loop.

Wanneer runBlocking gebruiken

runBlocking is gerechtvaardigd in drie scenario’s: het ingangspunt main() in consoletoepassingen, unittesten van suspend-functies en bridging — aanroep van suspend-code vanuit callback-gebaseerde of blokkerende bibliotheken. In Android-productiecode is gebruik op de hoofdthread ten strengste verboden.

ScenarioToepasbaarheidRisico’s
main() consoletoepassingJaGeen — dit is het ingangspunt, de thread blokkeert geen UI
JUnit-testsJaMinimaal — tests zijn per definitie synchroon
Android UI-ThreadNeeANR, vertragingen, bevriezing van de interface
Callback → CoroutineJa, met voorzichtigheidBlokkering van de threadpool bij langdurige bewerkingen

Gebruik voor Android-tests kotlinx-coroutines-test met TestDispatcher in plaats van runBlocking. Dit biedt controle over de tijd, automatisch resetten en testisolatie.

Alternatieven voor runBlocking

In de meeste scenario’s kan en moet runBlocking worden vervangen door asynchrone alternatieven. Voor Android zijn dit viewModelScope, lifecycleScope of CoroutineScope met de juiste dispatcher. Voor tests — TestCoroutineDispatcher en runTest.

kotlin
    // Slecht: runBlocking op Android hoofdthread
runBlocking(Dispatchers.Main) {
    val result = networkApi.fetchData()
    textView.setText(result)
}

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

De vervanging voor tests is runTest uit kotlinx-coroutines-test. Het creëert een TestCoroutineScope met virtuele tijd, waarmee vertragingen kunnen worden getest zonder echt wachten. Dit versnelt tests en maakt ze deterministisch.

Voorbeelden van runBlocking gebruik

Het meest voorkomende scenario is het testen van suspend-functies. runBlocking in tests maakt het mogelijk synchroon te wachten op het resultaat van een coroutine zonder de architectuur te wijzigen. Het tweede scenario zijn bibliotheken met een callback-API, waar suspend-functies worden aangeroepen vanuit een blokkerende context via runBlocking.

kotlin
// Test suspend-functie met 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)
    }
}

Gebruik voor de brug tussen de callback- en suspend-wereld CompletableDeferred in combinatie met runBlocking in plaats van callbacks — dit vereenvoudigt ketens van asynchrone bewerkingen en verbetert de leesbaarheid van de code.

Gevaren van verkeerd gebruik

Verkeerd gebruik van runBlocking is een van de veelgemaakte fouten bij de overgang van een blokkerende aanpak naar coroutines. De belangrijkste problemen: aanroep op de Android Main-Thread, nesten van runBlocking, gebruik binnen asynchrone functies en starten van langdurige bewerkingen via runBlocking.

  • ANR — runBlocking op de Android Main-Thread blokkeert UI-rendering gedurende meer dan 5 seconden
  • Deadlock — geneste runBlocking binnen een coroutine op dezelfde thread leidt tot wederzijdse blokkering
  • Verwarring met dispatchers — Dispatchers.Main binnen runBlocking in een achtergrondthread heeft geen Looper en crasht met een uitzondering
  • Geheugenlekken — runBlocking wordt niet automatisch geannuleerd bij vernietiging van Activity/Fragment

Gouden regel: runBlocking is een brug, geen vervanging. Gebruik het alleen voor het verbinden van blokkerende en niet-blokkerende werelden. Voor alle andere taken gebruik je launch, async of lifecycleScope.

Veelgestelde vragen

Waarom blokkeert runBlocking de thread en andere builders niet?

runBlocking is de enige builder die geen suspend-functie is. Het start een event-loop in de huidige thread en geeft de controle pas terug als alle coroutines zijn voltooid. launch en async geven onmiddellijk de controle terug en voeren de coroutine op de achtergrond uit.

Kan runBlocking worden gebruikt in Android ViewModel?

Niet aanbevolen. ViewModel heeft ingebouwde viewModelScope die automatisch coroutines beheert en annuleert bij vernietiging. runBlocking in ViewModel blokkeert de thread en reageert niet op annulering van de lifecycle.

Waarmee vervang ik runBlocking in unittesten?

Gebruik runTest uit de kotlinx-coroutines-test bibliotheek. Het biedt een TestCoroutineScope met virtuele tijdcontrole, automatische annulering en deterministische uitvoering.

Wat is event-loop in runBlocking?

Event-loop — de gebeurtenisverwerkingscyclus binnen runBlocking. Wanneer een coroutine wordt opgeschort (bijv. delay()), schakelt de event-loop naar de uitvoering van andere gereedstaande coroutines in dezelfde thread. Dit creëert de illusie van multitasking zonder threadwisseling.

Wat gebeurt er als runBlocking wordt aangeroepen binnen runBlocking?

Geneste runBlocking in een enkele thread creëert een deadlock — het externe blok wacht op het interne, maar het interne kan niet beginnen totdat het externe is voltooid. In verschillende threads is dit acceptabel, maar sterk afgeraden vanwege de moeilijkheid van debuggen.

Samenvatting

  • runBlocking — blokkerende Coroutine Builder, brug tussen blokkerende en asynchrone code
  • Event-loop runBlocking verwerkt coroutines coöperatief in één thread zonder wisseling
  • Toegestane scenario’s — main(), JUnit-tests, bridging vanuit callback-bibliotheken
  • Verboden scenario’s — Android UI-Thread, geneste aanroepen, langdurige bewerkingen
  • Alternatieven — lifecycleScope, viewModelScope, runTest voor tests
  • ANR-risico — runBlocking op de Main-Thread veroorzaakt bevriezing van de app na 5 seconden
  • Gebruik voor Android-productiecode asynchrone builders — runBlocking is niet bedoeld voor UI

We ontwikkelen een mobiele applicatie turnkey

IT Sectr creëert sinds 2017 iOS- en Android-applicaties voor startups en bedrijven. We adviseren u en stellen de beste oplossing voor.

Bespreek het project

Lees ook