훌륭한 개발자가 되기 위하여
코루틴 이해하기 본문
루틴 : 특정한 일을 하기 위한 일련의 처리 과정 (함수 or 매서드)
서브루틴 : 함수 내에서 함수가 호출될 경우 호출된 함수
fun routine() {
routineA() // routineA는 routine의 서브루틴
routineB() // routineB는 routine의 서브루틴
}
- 서브루틴은 한 번 실행되면 끝까지 실행된다.
- 루틴에 의해 서브루틴이 호출되면 루틴을 실행하던 스레드는 서브루틴을 실행하는데 사용되어 서브루틴의 실행이 완료될 때까지 다른 작업을 할 수 없다.

코루틴 : 함께 실행되는 루틴으로 서로 간에 스레드 사용을 양보하며 함께 실행된다.
fun main() = runBlocking<Unit> {
launch {
while (true) {
println("자식 코루틴에서 작업 실행 중")
yield()
}
}
while (true) {
println("부모 코루틴에서 작업 실행 중")
yield()
}
}

코루틴의 스레드 양보
- 코루틴은 작업 중간에 스레드의 사용이 불필요해지면 스레드를 양보한다.
👉 이 때 양보된 스레드는 다른 코루틴이 점유해 사용할 수 있다.
- 스레드를 양보하는 주체는 코루틴이다.
👉 스레드를 양보하기 위해서는 코루틴이 직접 스레드 양보를 위한 함수를 호출해야 한다.
delay 함수
- 작업을 일정 시간 동안 일시 중단해야 할 경우 delay 함수 를 사용할 수 있다.
- 코루틴이 delay함수를 호출하면 코루틴은 사용하던 스레드를 양보하고 설정된 시간 동안 일시 중단된다.
fun main() = runBlocking<Unit> {
val startTime = System.currentTimeMillis()
repeat(10) { repeatTime ->
launch {
delay(1000L)
println("[${getElapsedTime(startTime)}] 코루틴${repeatTime} 실행 완료")
}
}
}
fun getElapsedTime(startTime: Long): String = "지난 시간: ${System.currentTimeMillis() - startTime}ms"
![]() |
![]() |
✔ Thread.sleep 함수를 사용하면 스레드를 양보하지 않는다.
fun main() = runBlocking<Unit> {
val startTime = System.currentTimeMillis()
repeat(10) { repeatTime ->
launch {
Thread.sleep(1000L)
println("[${getElapsedTime(startTime)}] 코루틴${repeatTime} 실행 완료")
}
}
}
fun getElapsedTime(startTime: Long): String = "지난 시간: ${System.currentTimeMillis() - startTime}ms"
![]() |
![]() |
join, await
- Job의 join 함수나 Deferred의 await 함수가 호출되면 해당 함수를 호출한 코루틴은 스레드를 양보하고, join 또는 await의 대상이 된 코루틴이 완료될 때까지 일시 중단된다.
- 하나의 코루틴이 스레드를 양보하지 않으면 다른 코루틴은 스레드를 점유하지 못한다.
fun main() = runBlocking<Unit> {
val job = launch {
println("1. launch 코루틴 작업이 시작됐습니다.")
delay(1000L)
println("2. launch 코루틴 작업이 완료됐습니다.")
}
println("3. runBlocking 코루틴이 곧 일시 중단 되고 메인 스레드가 양보됩니다")
job.join()
println("4. runBlocking이 메인 스레드에 보내져 작업이 다시 재개됩니다")
}
![]() |
![]() |
yield 함수
- 몇가지 상황에서는 yield 함수 를 통해 직접 스레드를 양보하는 것이 필요하다
- 특히, 단일 스레드만 사용하는 상황에서는 명시적으로 yield를 사용해야 하는 경우가 종종 생긴다.
fun main() = runBlocking<Unit> {
val job = launch {
while(this.isActive) {
println("작업 중")
}
}
delay(100L)
job.cancel()
}
launch 코루틴에 스레드를 양보하는 부분이 없기 때문에 job.cancel() 이 실행되지 않음
// 실행 결과
작업 중
작업 중
작업 중
...

취소 되는 코드
fun main() = runBlocking<Unit> {
val job = launch(Dispatchers.Default) {
while (this.isActive) {
println("작업 중")
}
}
delay(100L)
job.cancel()
}

코루틴의 실행 스레드
- 코루틴이 일시 중단된 후 재개되면 CoroutineDispatcher 객체는 재개된 코루틴을 다시 스레드에 보낸다.
- 이 때, CoroutineDispatcher 객체는 코루틴을 사용할 수 있는 스레드 중 하나에 보내기 때문에, 코루틴이 재개된 후의 실행 스레드는 일시 중단되기 전의 스레드와 다를 수 있다.
- 코루틴의 실행 스레드는 고정이 아니다
- 스레드를 양보하지 않으면 실행 스레드가 바뀌지 않는다.
'안드로이드' 카테고리의 다른 글
| Jetpack Compose Stability (1) | 2025.01.20 |
|---|---|
| 공유 상태를 사용하는 코루틴의 문제와 해결책, 코루틴의 동작 방식 (0) | 2025.01.15 |
| 일시 중단 함수와 코루틴 (0) | 2025.01.13 |
| 코루틴 예외 처리 (0) | 2025.01.12 |
| 구조화된 동시성 (0) | 2025.01.11 |





