runBlocking — шта је то, блокирајући мост и како ради

Аутор: IT Sectr Објављено: 2026-06-22 Време читања: 7 мин

runBlocking — Coroutine Builder у Kotlin-у који блокира тренутну нит до завршетка прослеђене корутине. За разлику од launch и async, он није suspend-функција и може се позвати из обичног (blocking) кода. Према документацији JetBrains, 2024, runBlocking служи као мост између синхроног и асинхроног света, омогућавајући покретање корутина из main-функције и тестова.

Главно

  • runBlocking — блокирајући билдер, који ствара CoroutineScope и чека завршетак корутине
  • Блокирање нити — runBlocking задржава тренутну нит до потпуног завршетка корутине и свих подређених
  • Тачке улаза — main(), JUnit тестови и премошћавање између blocking и async кода
  • Забрањен на Main-нити Android-а — позив runBlocking у UI-нити изазива ANR
  • Алтернативе — lifecycleScope, viewModelScope, TestCoroutineDispatcher за Android

Шта је runBlocking?

runBlocking — је функција Kotlin-а која ствара нови CoroutineScope и покреће прослеђену корутину, блокирајући тренутну нит до њеног потпуног завршетка. За разлику од свих осталих Coroutine Builder-а, runBlocking није suspend-функција и може се позвати из обичног синхроног кода. Сигнатура runBlocking прима CoroutineContext и suspend-блок, враћајући резултат типа T.

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

runBlocking покреће нови event-loop у тренутној нити. Када корутина позове suspend-функцију (нпр. delay() или await()), runBlocking блокира нит и извршава друге заказане корутине у истој нити до наставка суспендоване. Ово је кооперативно блокирање — нит не мирује, већ обрађује друге корутине.

Како ради runBlocking

Унутрашњи механизам runBlocking се заснива на event-loop-у: при позиву suspend-функције runBlocking суспендује извршење тренутног блока и покреће друге корутине из реда. Када се suspend-функција заврши, извршење се наставља. Овај циклус се наставља док се све корутине не заврше.

Event-loop испод хаубе

runBlocking користи сопствени једнонитни пул за извршавање корутина. За разлику од Dispatchers.IO или Default, runBlocking не пребацује нити — обрађује све корутине у тренутној нити, преплићући њихово извршење. Ово је једини билдер који гарантује извршење у истој нити.

kotlin
fun main() {
    val threadName = Thread.currentThread().getName()
    println("Пре runBlocking на $threadName")

    val result = runBlocking {
        println("Унутар runBlocking на ${Thread.currentThread().getName()}")
        delay(500L)
        "Done"
    }

    println("Након runBlocking: $result")
}

Излаз ће показати да се сва три println извршавају на једној нити. runBlocking не пребацује нит, већ организује кооперативно мултизадавање унутар једне нити помоћу event-loop-а.

Када користити runBlocking

runBlocking је оправдан у три сценарија: тачка улаза main() у конзолним апликацијама, јединични тестови suspend-функција и премошћавање — позив suspend-кода из callback-базираних или blocking библиотека. У production коду Android-а употреба на главној нити је категорички забрањена.

СценариоПримењивостРизик
main() конзолне апликацијеДаНема — ово је тачка улаза, нит не блокира UI
JUnit тестовиДаМинимални — тестови су по дефиницији синхрони
Android UI-нитНеANR, кашњења, замрзавање интерфејса
Callback → CoroutineДа, с опрезомБлокирање пула нити при дуготрајним операцијама

За Android тестове користите kotlinx-coroutines-test са TestDispatcher уместо runBlocking. Ово даје контролу над временом, аутоматско ресетовање и изолацију тестова.

Алтернативе runBlocking

У већини сценарија runBlocking се може и треба заменити асинхроним алтернативама. За Android су то viewModelScope, lifecycleScope или CoroutineScope са правим диспечером. За тестове — TestCoroutineDispatcher и runTest.

kotlin
    // Лоше: runBlocking на главној нити Android-а
runBlocking(Dispatchers.Main) {
    val result = networkApi.fetchData()
    textView.setText(result)
}

// Добро: lifecycleScope
lifecycleScope.launch {
    val result = withContext(Dispatchers.IO) { networkApi.fetchData() }
    textView.setText(result)
}

Замена за тестове је runTest из kotlinx-coroutines-test. Он ствара TestCoroutineScope са виртуелним временом, омогућавајући тестирање кашњења без реалног чекања. Ово убрзава тестове и чини их детерминистичким.

Примери употребе runBlocking

Најчешћи сценарио — тестирање suspend-функција. runBlocking у тестовима омогућава синхроно чекање резултата корутине без промене архитектуре. Други сценарио — библиотеке са callback API, где се suspend-функције позивају из blocking контекста преко runBlocking-а.

kotlin
// Тестирање suspend функције са 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)
    }
}

За премошћавање између callback и suspend света користите CompletableDeferred у комбинацији са runBlocking уместо callback-ова — ово поједностављује ланце асинхроних операција и повећава читљивост кода.

Опасности неправилне употребе

Неправилна употреба runBlocking-а је једна од честих грешака при преласку са blocking приступа на корутине. Главни проблеми: позив на Main-нити Android-а, угњежђавање runBlocking-а, употреба унутар асинхроних функција и покретање дуготрајних операција кроз runBlocking.

  • ANR — runBlocking на Main-нити Android-а блокира приказивање UI-ја на више од 5 секунди
  • Deadlock — угњеждени runBlocking унутар корутине на истој нити доводи до међусобног блокирања
  • Забуна са диспечерима — Dispatchers.Main унутар runBlocking-а у позадинској нити нема Looper и пада са изузетком
  • Цурење меморије — runBlocking се не отказује аутоматски при уништењу Activity/Fragment-а

Златно правило: runBlocking је мост, а не замена. Користите га само за повезивање blocking и non-blocking светова. За све остале задатке примењујте launch, async или lifecycleScope.

Често постављана питања

Зашто runBlocking блокира нит, а остали билдери — не?

runBlocking је једини билдер који није suspend-функција. Он покреће event-loop у тренутној нити и не враћа контролу док се све корутине не заврше. launch и async враћају контролу одмах, извршавајући корутину у позадини.

Може ли се користити runBlocking у Android ViewModel-у?

Не препоручује се. ViewModel има уграђени viewModelScope, који аутоматски управља корутинама и отказује их при уништењу. runBlocking у ViewModel-у блокира нит и не реагује на отказивање lifecycle-а.

Чиме заменити runBlocking у јединичним тестовима?

Користите runTest из библиотеке kotlinx-coroutines-test. Он пружа TestCoroutineScope са контролом виртуелног времена, аутоматским отказивањем и детерминистичким извршењем.

Шта је event-loop у runBlocking-у?

Event-loop — циклус обраде догађаја унутар runBlocking-а. Када се корутина суспендује (нпр. delay()), event-loop се пребацује на извршење других спремних корутина у истој нити. Ово ствара илузију мултизадавања без пребацивања нити.

Шта се дешава при позиву runBlocking унутар runBlocking-а?

Угњеждени runBlocking у једној нити ствара deadlock — спољашњи блок чека унутрашњи, али унутрашњи не може да почне док се спољашњи не заврши. У различитим нитима је ово прихватљиво, али изузетно се не препоручује због тежине отклањања грешака.

Закључак

  • runBlocking — блокирајући Coroutine Builder, мост између blocking и асинхроног кода
  • Event-loop runBlocking-а обрађује корутине кооперативно у једној нити без пребацивања
  • Дозвољени сценарији — main(), JUnit тестови, премошћавање из callback библиотека
  • Забрањени сценарији — Android UI-нит, угњеждени позиви, дуготрајне операције
  • Алтернативе — lifecycleScope, viewModelScope, runTest за тестове
  • ANR ризик — runBlocking на Main-нити изазива замрзавање апликације после 5 секунди
  • За production код Android-а користите асинхроне билдере — runBlocking није намењен за UI

Развићемо мобилну апликацију под кључ

IT Sectr креира iOS и Android апликације за стартапе и предузећа од 2017. године. Саветоваћемо вас и предложити најбоље решење.

Разговарајте о пројекту

Прочитајте такође