runBlocking — co to je, blokující most a jak funguje

Autor: IT Sectr Publikováno: 2026-06-22 Doba čtení: 7 min

runBlocking — Coroutine Builder v Kotlinu, který blokuje aktuální vlákno do dokončení předané korutiny. Na rozdíl od launch a async není funkcí suspend a může být volán z běžného (blokujícího) kódu. Podle dokumentace JetBrains, 2024, slouží runBlocking jako most mezi synchronním a asynchronním světem a umožňuje spouštět korutiny z funkce main a testů.

Hlavní body

  • runBlocking — blokující builder, který vytváří CoroutineScope a čeká na dokončení korutiny
  • Blokování vlákna — runBlocking zadržuje aktuální vlákno do úplného dokončení korutiny a všech podřízených
  • Vstupní body — main(), JUnit testy a přemostění mezi blokujícím a asynchronním kódem
  • Zakázáno na Main-Thread Android — volání runBlocking ve vlákně UI způsobuje ANR
  • Alternativy — lifecycleScope, viewModelScope, TestCoroutineDispatcher pro Android

Co je runBlocking?

runBlocking — je funkce Kotlinu, která vytváří nový CoroutineScope a spouští předanou korutinu, blokuje aktuální vlákno do jejího úplného dokončení. Na rozdíl od všech ostatních Coroutine Builder není runBlocking funkcí suspend a může být volán z běžného synchronního kódu. Signatura runBlocking přijímá CoroutineContext a suspend-blok a vrací výsledek typu T.

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

runBlocking spouští novou smyčku událostí (event-loop) v aktuálním vlákně. Když korutina zavolá funkci suspend (např. delay() nebo await()), runBlocking zablokuje vlákno a provádí další naplánované korutiny ve stejném vlákně, dokud není pozastavená obnovena. Toto je kooperativní blokování — vlákno není nečinné, ale zpracovává jiné korutiny.

Jak runBlocking funguje

Vnitřní mechanismus runBlocking je založen na event-loop: při volání funkce suspend runBlocking pozastaví provádění aktuálního bloku a spouští další korutiny z fronty. Po dokončení funkce suspend je provádění obnoveno. Tento cyklus pokračuje, dokud nejsou dokončeny všechny korutiny.

Event-loop pod kapotou

runBlocking používá vlastní jednovláknový fond pro provádění korutin. Na rozdíl od Dispatchers.IO nebo Default runBlocking nemění vlákna — zpracovává všechny korutiny v aktuálním vlákně, střídá jejich provádění. Toto je jediný builder, který zaručuje provádění ve stejném vlákně.

kotlin
fun main() {
    val threadName = Thread.currentThread().getName()
    println("Před runBlocking na $threadName")

    val result = runBlocking {
        println("Uvnitř runBlocking na ${Thread.currentThread().getName()}")
        delay(500L)
        "Done"
    }

    println("Po runBlocking: $result")
}

Výstup ukáže, že všechny tři println se provádějí na jednom vlákně. runBlocking nemění vlákno, ale organizuje kooperativní multitasking v rámci jednoho vlákna pomocí event-loop.

Kdy použít runBlocking

runBlocking je opodstatněný ve třech scénářích: vstupní bod main() v konzolových aplikacích, jednotkové testy funkcí suspend a přemostění — volání kódu suspend z callbackových nebo blokujících knihoven. V produkčním kódu Android je použití na hlavním vlákně kategoricky zakázáno.

ScénářPoužitelnostRizika
main() konzolové aplikaceAnoŽádné — to je vstupní bod, vlákno neblokuje UI
JUnit testyAnoMinimální — testy jsou z definice synchronní
Android UI-ThreadNeANR, zpoždění, zamrznutí rozhraní
Callback → CoroutineAno, opatrněBlokování fondu vláken při dlouhých operacích

Pro Android testy používejte kotlinx-coroutines-test s TestDispatcher místo runBlocking. To poskytuje kontrolu nad časem, automatický reset a izolaci testů.

Alternativy k runBlocking

Ve většině scénářů lze a je třeba runBlocking nahradit asynchronními alternativami. Pro Android jsou to viewModelScope, lifecycleScope nebo CoroutineScope se správným dispečerem. Pro testy — TestCoroutineDispatcher a runTest.

kotlin
    // Špatně: runBlocking na hlavním vlákně Android
runBlocking(Dispatchers.Main) {
    val result = networkApi.fetchData()
    textView.setText(result)
}

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

Náhradou pro testy je runTest z kotlinx-coroutines-test. Vytváří TestCoroutineScope s virtuálním časem, což umožňuje testovat zpoždění bez reálného čekání. To testy zrychluje a činí je deterministickými.

Příklady použití runBlocking

Nejčastějším scénářem je testování funkcí suspend. runBlocking v testech umožňuje synchronně počkat na výsledek korutiny bez změny architektury. Druhým scénářem jsou knihovny s callback API, kde jsou funkce suspend volány z blokujícího kontextu přes runBlocking.

kotlin
// Test suspend funkce s 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)
    }
}

Pro přemostění mezi callback a suspend světem používejte CompletableDeferred v kombinaci s runBlocking místo callbacků — to zjednodušuje řetězce asynchronních operací a zvyšuje čitelnost kódu.

Nebezpečí nesprávného použití

Nesprávné použití runBlocking je jednou z častých chyb při přechodu z blokujícího přístupu na korutiny. Hlavní problémy: volání na Main-Thread Android, vnořování runBlocking, použití uvnitř asynchronních funkcí a spouštění dlouhých operací přes runBlocking.

  • ANR — runBlocking na Main-Thread Android blokuje vykreslování UI na více než 5 sekund
  • Deadlock — vnořený runBlocking uvnitř korutiny na stejném vlákně vede k vzájemnému blokování
  • Zmatek s dispečery — Dispatchers.Main uvnitř runBlocking v vlákně na pozadí nemá Looper a končí výjimkou
  • Úniky paměti — runBlocking není automaticky zrušen při zničení Activity/Fragment

Zlaté pravidlo: runBlocking je most, nikoli náhrada. Používejte ho pouze pro propojení blokujícího a neblokujícího světa. Pro všechny ostatní úkoly používejte launch, async nebo lifecycleScope.

Často kladené otázky

Proč runBlocking blokuje vlákno, zatímco jiné buildery ne?

runBlocking je jediný builder, který není funkcí suspend. Spouští event-loop v aktuálním vlákně a nevrací řízení, dokud nejsou dokončeny všechny korutiny. launch a async vracejí řízení okamžitě a provádějí korutinu na pozadí.

Lze runBlocking použít v Android ViewModel?

Nedoporučuje se. ViewModel má vestavěný viewModelScope, který automaticky spravuje korutiny a ruší je při zničení. runBlocking ve ViewModel blokuje vlákno a nereaguje na zrušení lifecycle.

Čím nahradit runBlocking v jednotkových testech?

Použijte runTest z knihovny kotlinx-coroutines-test. Poskytuje TestCoroutineScope s řízením virtuálního času, automatickým zrušením a deterministickým prováděním.

Co je event-loop v runBlocking?

Event-loop — smyčka zpracování událostí uvnitř runBlocking. Když je korutina pozastavena (např. delay()), event-loop přepne na provádění jiných připravených korutin ve stejném vlákně. To vytváří iluzi multitaskingu bez přepínání vláken.

Co se stane při volání runBlocking uvnitř runBlocking?

Vnořený runBlocking v jednom vlákně vytváří deadlock — vnější blok čeká na vnitřní, ale vnitřní nemůže začít, dokud vnější neskončí. V různých vláknech je to přijatelné, ale důrazně se nedoporučuje kvůli obtížnosti ladění.

Shrnutí

  • runBlocking — blokující Coroutine Builder, most mezi blokujícím a asynchronním kódem
  • Event-loop runBlocking zpracovává korutiny kooperativně v jednom vlákně bez přepínání
  • Povolené scénáře — main(), JUnit testy, přemostění z callback knihoven
  • Zakázané scénáře — Android UI-Thread, vnořená volání, dlouhé operace
  • Alternativy — lifecycleScope, viewModelScope, runTest pro testy
  • Riziko ANR — runBlocking na Main-Thread způsobí zamrznutí aplikace po 5 sekundách
  • Pro produkční kód Android používejte asynchronní buildery — runBlocking není určen pro UI

Vyvineme mobilní aplikaci na klíč

IT Sectr vytváří aplikace pro iOS a Android pro startupy a podniky od roku 2017. Poradíme vám a navrhneme nejlepší řešení.

Prodiskutovat projekt

Přečtěte si také