Coroutines — кључни појмови, Job и Dispatchers у Kotlin-у

Аутор: IT Sectr Објављено: 2026-03-16 Време читања: 8 мин

Coroutines (корутине) — лагане нити Kotlin-а за асинхроно програмирање, доступне кроз библиотеку kotlinx.coroutines. Према JetBrains Kotlin Documentation, 2026, Coroutines омогућавају заустављање извршења функције без блокирања нити, за разлику од традиционалних Thread-ова. Корутине се покрећу на ограниченом пулу нити, што их чини хиљаду пута лакшима од нативних нити. Kotlin Coroutines су потпуно интегрисане са Android Jetpack, Retrofit, Room и другим популарним библиотекама екосистема Android.

Главно

  • Coroutines — лагане нити Kotlin-а за асинхрони код без блокирања
  • suspend функција — функција способна да се заустави и настави без блокирања нити
  • Dispatcher одређује пул нити за извршење корутине
  • Job — дескриптор корутине са подршком за отказивање и праћење стања
  • CoroutineScope управља животним циклусом корутина и њиховим отказивањем при завршетку

Шта су корутине Kotlin-а

Coroutines (корутине) — механизам асинхроног програмирања у Kotlin-у, имплементиран у библиотеци kotlinx.coroutines. За разлику од нити оперативног система, корутине нису везане за одређену нит: могу се зауставити на једној нити и наставити на другој. Једна нит може извршавати хиљаде корутина, пребацујући се између њих са минималним додатним оптерећењем.

Корутине су се појавиле у Kotlin 1.3 (2018) као експериментална функција и постале стабилне у Kotlin 1.5 (2021). Coroutines решавају проблем callback hell слично async/await, али пружају богатији API: канали (Channel), Flow, обрада изузетака у хијерархији Job и директна интеграција са Android Lifecycle.

Према JetBrains (2025), свака корутина троши око 100 бајтова меморије у поређењу са 1+ MB за нативну нит. Ово омогућава покретање милиона корутина у једној апликацији без ризика од OutOfMemoryError. Управо лакоћа корутина их чини пожељним алатом за асинхроност у Android-у.

Како корутине раде испод хаубе

Свака Kotlin корутина се компајлира у state machine кроз Continuation Passing Style (CPS). Компајлер додаје скривени параметар Continuation свакој suspend функцији. Continuation садржи тачку наставка и све локалне променљиве. Када се корутина заустави, runtime чува Continuation, а када се настави — враћа га на било којој доступној нити из Dispatcher пула.

Suspend функције: заустављање и наставак

suspend — кључна реч Kotlin-а која означава функцију као заустављиву. Таква функција се може позвати само из друге suspend функције или из корутине. Унутар suspend функције могу се позивати друге suspend функције било којим редоследом, и свака тачка позива је потенцијална тачка заустављања.

Механика је једноставна: када suspend функција позове другу suspend функцију, она се зауставља у тој тачки, ослобађајући нит. Након завршетка позване функције, runtime наставља извршење са сачуваног места. Ово се назива cooperative cancellation — ниједна нит није блокирана.

  • Заустављање — корутина ослобађа нит без блокирања
  • Наставак — корутина наставља са истог места где се зауставила
  • Нит — корутина се може зауставити на нити А и наставити на нити Б
  • Изузеци — обрађују се кроз try/catch исто као у синхроном коду

Важно: suspend функција није асинхрона подразумевано. Редослед извршења остаје секвенцијалан ако се не користе launch или async. suspend само омогућава функцији да буде заустављена без блокирања нити и да буде део корутинског контекста. Continuation Passing Style је модел компајлације при којем свака suspend функција добија скривени callback Continuation, а компајлер генерише коначни аутомат за управљање заустављањима и наставцима.

CoroutineScope и Structured Concurrency

CoroutineScope — контекст који дефинише животни циклус корутина. Све корутине морају бити покренуте унутар scope-а. Када се scope откаже (нпр. при завршетку Activity), све његове подређене корутине се аутоматски отказују. Ово спречава цурење позадинских задатака. Android Jetpack пружа готове scope-ове за сваку компоненту: viewModelScope за ViewModel и lifecycleScope за Activity и Fragment, који се аутоматски отказују при уништењу одговарајуће компоненте.

Structured Concurrency — принцип који гарантује да се корутина неће завршити док се све њене подређене корутине не заврше. Хијерархија Job формира стабло: коренска корутина ствара parent job, подређене — child jobs. Отказивање parent job-а се шири на сву децу. Structured Concurrency је фундаментална разлика између корутина и нити.

ScopeГде се користиОтказивање
GlobalScopeСамо за daemon задаткеНе отказује се аутоматски
viewModelScopeAndroid ViewModelПри чишћењу ViewModel-а
lifecycleScopeAndroid Activity/FragmentПри уништењу lifecycle-а
coroutineScopeУнутар suspend функцијеПри отказивању родитељског job-а

SupervisorJob за обраду грешака

Обични Job при грешци једне подређене корутине отказује све siblings. SupervisorJob је изузетак: квар у једној подређеној корутини не утиче на остале. Ово је важно када се више независних задатака извршава паралелно и један може да падне без потребе за отказивањем осталих.

Dispatchers и градитељи корутина

Dispatchers одређују на којим нитима се извршавају корутине. Dispatchers.Main — главна UI нит Android-а. Dispatchers.IO — пул за блокирајуће операције (мрежа, диск). Dispatchers.Default — за CPU интензивне задатке. Dispatchers.Unconfined — креће у тренутној нити, али не гарантује фиксацију на њој. Правилан избор Dispatcher-а је критичан за перформансе: IO задатак на Default-у блокираће пул за израчунавања, а CPU задатак на IO-у створиће додатне нити.

withContext — функција за пребацивање Dispatcher-а унутар корутине. На пример, suspend функција која парсира JSON може се пребацити на Dispatchers.Default током израчунавања и вратити на Dispatchers.Main за ажурирање UI-ја. withContext је најчешће коришћени градитељ у Android развоју.

Три главна градитеља корутина

launch — покреће корутину, враћа Job, не враћа резултат (fire-and-forget). async — покреће корутину, враћа Deferred из којег се може добити резултат кроз await. runBlocking — блокира тренутну нит за извршење корутине (само за тестове и main функције). Избор градитеља зависи од сценарија: launch одговара за догађаје и ажурирања, async — за задатке са резултатом, runBlocking — само за тестове или улазне тачке.

Примери кода са корутинама у Kotlin-у

Размотримо три практична сценарија: основна корутина са launch, паралелни позив са async и обрада грешака са SupervisorJob.

Покретање корутине са launch

viewModelScope.launch покреће корутину у контексту ViewModel-а. При чишћењу ViewModel-а корутина се аутоматски отказује.

kotlin
class ProfileViewModel : ViewModel() {
    fun loadUser() {
        viewModelScope.launch(Dispatchers.IO) {
            val user = api.fetchUser()
            withContext(Dispatchers.Main) {
                showUser(user)
            }
        }
    }
}

Паралелни захтеви са async

coroutineScope са async покреће три захтева паралелно. Резултати се прикупљају кроз .await(). Ако било који захтев падне, сви се отказују.

kotlin
suspend fun loadDashboard(): Dashboard = coroutineScope {
    val user = async { api.fetchUser() }
    val posts = async { api.fetchPosts() }
    val stats = async { api.fetchStats() }
    Dashboard(user.await(), posts.await(), stats.await())
}

Обрада грешака са SupervisorJob

SupervisorJob омогућава свакој корутини да се заврши независно. Грешка у једном захтеву не отказује остале.

kotlin
val scope = CoroutineScope(SupervisorJob() + Dispatchers.IO)
scope.launch {
    try { api.fetchUsers() } catch (e: Exception) { log(e) }
}
scope.launch {
    try { api.fetchPosts() } catch (e: Exception) { log(e) }
}

Корутине vs нити: поређење и сценарији

Нити (Thread) — примитив оперативног система. Свака нит има сопствени стек (~1 MB) и захтева системски позив за креирање и пребацивање. Корутине — примитив језика, невезан за ОС. Оне користе Continuation за чување стања и пребацују се на нивоу runtime-а без системских позива.

  • Меморија — нит ~1 MB, корутина ~100 бајтова. Разлика 10 000 пута
  • Креирање — нит ~1 µс syscall, корутина ~0.01 µс на нивоу JVM
  • Пребацивање — нит ~0.1 µс (syscall), корутина ~0.001 µс (continuation)
  • Максимум — хиљаде нити vs милиони корутина на уређају
  • Отказивање — нит се не може отказати споља (deprecated Thread.stop), корутина се може кроз Job.cancel()

Према Google (2025), коришћење корутина уместо нити смањује потрошњу меморије за позадинске задатке у Android апликацијама за 90–95%. Све модерне Android библиотеке (Retrofit, Room, WorkManager) имају уграђену подршку за корутине кроз suspend функције. Ktor (клијентски HTTP фрејмворк JetBrains-а) је такође у потпуности изграђен на корутинама, пружајући suspend-функције за сваки захтев без callback API-ја. Room подржава корутине кроз suspend-функције у DAO-у, омогућавајући извршавање упита бази података без блокирања главне нити.

Када користити нити уместо корутина

Нити остају неопходне за нативни код кроз JNI, блокирајуће CPU интензивне позиве без временског ограничења (рендеровање видеа, симулације) и при интеграцији са C библиотекама. За све остало — корутине.

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

Чим се корутина разликује од нити?

Корутина — заустављива јединица посла која се извршава на постојећој нити. Нит је системски ресурс са сопственим стеком. Корутине су хиљадама пута лакше од нити и не блокирају ресурсе при заустављању.

Шта је Dispatchers.IO и по чему се разликује од Default-а?

Dispatchers.IO је намењен за блокирајуће I/O операције (мрежа, датотеке) и може креирати нове нити по потреби. Dispatchers.Default има фиксан пул (број процесорских језгара) за CPU интензивна израчунавања.

Како отказати покренуту корутину?

Job.cancel() отказује корутину и сву њену децу. За проверу отказивања унутар корутине користите ensureActive() — баца CancellationException ако је корутина отказана.

Могу ли се користити корутине са RxJava?

Да — кроз библиотеку kotlinx-coroutines-rx3. Она пружа функције awaitSingle, awaitFirst и друге за конверзију Observable/Single у suspend функције и обрнуто кроз flowable.

Шта је Flow у корутинама?

Flow — хладни асинхрони ток података, аналог RxJava Observable-а за корутине. Flow емитује вредности секвенцијално и завршава се изузетком или успехом. Подржава map, filter, catch и друге операторе.

Закључак

  • Coroutines — лагане нити Kotlin-а са заустављањем без блокирања кроз Continuation Passing Style
  • suspend — кључна реч за означавање заустављивих функција
  • Dispatchers управљају пулом нити: Main, IO, Default редом
  • CoroutineScope везује животни циклус корутина за компоненту (Activity, ViewModel)
  • launch покреће корутину без резултата, async/await — са резултатом
  • Structured Concurrency гарантује хијерархијско отказивање подређених корутина
  • Корутине vs нити — корутине су 10 000 пута лакше и стандард су за Android

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

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

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

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