Skip to the content.

처음 만나는 코루틴

예제 1: 간단한 코루틴

아주 간단한 코루틴을 수행해봅시다. 코루틴을 만드는 가장 간단한 함수는 runBlocking이라고 합니다. 이렇게 코루틴을 만드는 함수를 코루틴 빌더라고 합니다. runBlocking은 코루틴을 만들고 코드 블록이 수행이 끝날 때까지 runBlocking 다음의 코드를 수행하지 못하게 막습니다. 그래서 블로킹(blocking)인거죠.

import kotlinx.coroutines.* fun main() = runBlocking { println(Thread.currentThread().name) println("Hello") }

스레드 이름이 main @coroutine1입니다.

메인 스레드에서 수행되는데 뒤에 수식어 @coroutine1이 붙어 있습니다.

예제 2: 코루틴 빌더의 수신 객체

runBlocking안에서 this를 수행하면 코루틴이 수신 객체(Receiver)인 것을 알 수 있습니다.

import kotlinx.coroutines.* fun main() = runBlocking { println(this) println(Thread.currentThread().name) println("Hello") }

"coroutine#1":BlockingCoroutine{Active}@3930015a 이런 형태의 결과가 나옵니다.

BlockingCoroutineCoroutineScope의 자식입니다. 코틀린 코루틴을 쓰는 모든 곳에는 코루틴 스코프(CoroutineScope)가 있다고 생각하면 됩니다.

코루틴의 시작은 코루틴 스코프다. 외웁시다.

예제 3: 코루틴 컨텍스트

코루틴 스코프는 코루틴을 제대로 처리하기 위한 정보, 코루틴 컨텍스트(CoroutineContext)를 가지고 있습니다. 수신 객체의 coroutineContext를 호출해 내용을 확인해봅시다.

import kotlinx.coroutines.* fun main() = runBlocking { println(coroutineContext) println(Thread.currentThread().name) println("Hello") }

예제 4: launch 코루틴 빌더

이제 코루틴 내에서 다른 코루틴을 수행해 봅시다.

이번에는 launch란 빌더를 사용해서 코드를 수행합니다. launch는 코루틴 빌더입니다. 새로운 코루틴을 만들기 때문에 새로운 코루틴 스코프를 만들게 되고요. launch는 “할 수 있다면 다른 코루틴 코드를 같이 수행”시키는 코루틴 빌더입니다.

import kotlinx.coroutines.* fun main() = runBlocking { launch { println("launch: ${Thread.currentThread().name}") println("World!") } println("runBlocking: ${Thread.currentThread().name}") println("Hello") }

launch 코루틴 빌더에 있는 내용이 runBlocking이 있는 메인 흐름 보다 늦게 수행된 것을 볼 수 있습니다. 둘 다 메인 스레드(main)를 사용하기 때문에 runBlocking의 코드들이 메인 스레드를 다 사용할 때 까지 launch의 코드 블록이 기다리는 것입니다.

launch를 이용해 동시에 여러 코드를 수행하는 것은 다음에 다루겠습니다.

runBlockingHello를 출력하고 나서 종료하지는 않고 launch 코드블록의 내용이 다 끝날 때까지 기다립니다.

예제 5: delay 함수

Hello를 조금 더 늦게 수행시키기 위해서는 delay 함수를 호출해 봅시다. 인자로 밀리세컨드 단위의 시간을 지정할 수 있습니다.

import kotlinx.coroutines.* fun main() = runBlocking { launch { println("launch: ${Thread.currentThread().name}") println("World!") } println("runBlocking: ${Thread.currentThread().name}") delay(500L) println("Hello") }
println("runBlocking: ${Thread.currentThread().name}")
delay(500L)

프린트 문이 호출된 이후 delay가 호출되는데 이때 runBlocking의 코루틴이 잠이 들게 되고 launch의 코드 블록이 먼저 수행됩니다.

예제 6: 코루틴 내에서 sleep

우리가 잘 아는 Thread.sleep을 호출하면 어떻게 될까요?

import kotlinx.coroutines.* fun main() = runBlocking { launch { println("launch: ${Thread.currentThread().name}") println("World!") } println("runBlocking: ${Thread.currentThread().name}") Thread.sleep(500) println("Hello") }

우리가 원하는 결과가 나오지 않았을 것입니다. Thread.sleep을 하면 코루틴이 아무 일을 하지 않는 동안에도 스레드를 양보하지 않고 독점합니다.

예제 7: 한번에 여러 launch

1, 2, 3을 순서대로 수행시켜봅시다.

import kotlinx.coroutines.* fun main() = runBlocking { launch { println("launch1: ${Thread.currentThread().name}") delay(1000L) println("3!") } launch { println("launch2: ${Thread.currentThread().name}") println("1!") } println("runBlocking: ${Thread.currentThread().name}") delay(500L) println("2!") }

딜레이 값을 바꿔 보면 suspend된 이후 깨어나는 순서에 따라 출력 결과가 달라집니다.

예제 8: 상위 코루틴은 하위 코루틴을 끝까지 책임진다.

runBlocking 안에 두 launch가 속해 있는데 계층화되어 있어 구조적입니다. runBlocking은 그 속에 포함된 launch가 다 끝나기 전까지 종료되지 않습니다.

import kotlinx.coroutines.* fun main() { runBlocking { launch { println("launch1: ${Thread.currentThread().name}") delay(1000L) println("3!") } launch { println("launch2: ${Thread.currentThread().name}") println("1!") } println("runBlocking: ${Thread.currentThread().name}") delay(500L) println("2!") } print("4!") }

예제 9: suspend 함수

delay, launch 등 지금까지 봤던 함수들은 코루틴 내에서만 호출 할 수 있습니다. 그럼 이 함수들을 포함한 코드들을 어떻게 함수로 분리할 수 있을까요?

코드의 일부를 함수로 분리할 때는 함수의 앞에 suspend 키워드를 붙이면 됩니다.

import kotlinx.coroutines.* suspend fun doThree() { println("launch1: ${Thread.currentThread().name}") delay(1000L) println("3!") } suspend fun doOne() { println("launch1: ${Thread.currentThread().name}") println("1!") } suspend fun doTwo() { println("runBlocking: ${Thread.currentThread().name}") delay(500L) println("2!") } fun main() = runBlocking { launch { doThree() } launch { doOne() } doTwo() }

doOnedelay와 같은 함수(suspend인 함수)를 호출하지 않았기 때문에 suspend를 붙이지 않은 일반 함수로 해도 됩니다.

만약 suspend 함수를 다른 함수에서 호출하려면 그 함수가 suspend 함수이거나 코루틴 빌더를 통해 코루틴을 만들어야 합니다.