최종 수정 날짜 : 2022-05-02 13:40:24 +0900
Coroutine Job
코루틴에서 Job은 백그라운드 작업의 단위를 의미하며 작업이 완료되거나 취소됐을 때 끝나는 생명주기(life-cycle)를 가지고 있다.
Job을 인스턴스화하는 기본적인 방법은 아래와 같다.
Coroutine job
:launch
코루틴 빌더를 이용해 인스턴스 생성CompletableJob
:Job()
의 생성자를 이용한 인스턴스 생성- Job()의 코드를 살펴보면 아래와 같다.
1
public fun Job(parent: Job? = null): CompletableJob = JobImpl(parent)
- Job()의 코드를 살펴보면 아래와 같다.
job은 기본적으로 결괏값을 반환하지 않지만, 결괏값을 반환하려면 async
코루틴 빌더와 같이 Deferred
를 사용해 결괏값을 받을 수도 있다.
Job은 부모(Parent)/자식(Child) 관계가 있다.
1
2
3
4
5
6
7
8
// 부모 (Parent)
val parent = CoroutineScope(Dispatchers.Default).launch {
[...]
// 자식 (Child)
val child = launch {
[...]
}
}
부모가 취소되거나 예외가 발생하면 하위 자식들도 동시에 종료가 되어 실행되지 않는다.
- 정상적으로 실행 시
정상실행 코드
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
import kotlinx.coroutines.* fun main() = runBlocking { CoroutineScope(Dispatchers.Default).launch { val job2 = launch { println("job2 start") delay(2000) println("Coroutine 2") } job2.join() println("Coroutine 1") }.join() println("Main") }
결과
1 2 3 4
job2 start Coroutine 2 Coroutine 1 Main
- 부모에서 예외 발생 시
예외발생 코드
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
import kotlinx.coroutines.* fun main() = runBlocking { CoroutineScope(Dispatchers.Default).launch { val job2 = launch { println("job2 start") delay(2000) println("Coroutine 2") } throw Exception() job2.join() println("Coroutine 1") }.join() println("Main") }
결과
- 부모에서 취소 발생 시
취소발생 코드
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
import kotlinx.coroutines.* import kotlin.coroutines.cancellation.CancellationException fun main() = runBlocking { CoroutineScope(Dispatchers.Default).launch { try { val job2 = launch { println("job2 start") delay(2000) println("Coroutine 2") } cancel() job2.join() println("Coroutine 1") } catch (e: CancellationException) { println("예외 : ${e.stackTraceToString()}") } }.join() println("Main") }
결과
자식이 취소가 될 경우에는 해당 Job만 취소되지만 CancellationException
을 제외한 나머지 모든 예외는 부모까지 모두 종료가 된다.
- 자식에서 취소를 발생시킨 경우
코드
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
import kotlinx.coroutines.* import kotlin.coroutines.cancellation.CancellationException fun main() = runBlocking { CoroutineScope(Dispatchers.Default).launch { val job2 = launch { println("job2 start") // cancel() 또는 throw CancellationException() 시에도 취소가 됨 // throw CancellationException() // cancel() delay(2000) println("Coroutine 2") } job2.cancel() println("Coroutine 1") }.join() println("Main") }
결과
1 2 3 4
// job2만 취소가 됨 job2 start Coroutine 1 Main
- 자식에서
CancellationException
이 아닌 다른 예외가 발생한 경우코드
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
import kotlinx.coroutines.* fun main() = runBlocking { CoroutineScope(Dispatchers.Default).launch { val job2 = launch { println("job2 start") throw Exception() delay(2000) println("Coroutine 2") } job2.join() println("Coroutine 1") }.join() println("Main") }
결과
즉, 자식에서 CancellationException
예외를 제외한 다른 예외가 발생할 경우 취소가 부모로 전파
되고, 부모가 취소되면서 하위 모든 자식 코루틴이 종료된다.
자식에서 예외가 발생해 부모의 Job까지 취소되는 것을 원하지 않는 경우 SupervisorJob
을 이용해 예외가 발생한 Job만 취소할 수 있다.
- 단, 부모에서
SupervisorJob
을 사용하더라도 하위 자식들의 job들은 취소가 된다.
Job States
Job에도 활성(Active), 완료(Complete), 취소(Cancel) 상태가 존재한다. 전체적인 상태 정보는 아래와 같다.
보통, 일반적으로 사용할 경우 생성과 동시에 활성(Active)상태이지만 코루틴 빌더의 Start 파라미터에 CoroutineStart.LAZY
옵션을 줄 경우 join()
또는 start()
메소드를 실행해야만 Job이 실행된다.
코드
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import kotlinx.coroutines.*
fun main() = runBlocking {
CoroutineScope(Dispatchers.Default).launch {
val job2 = launch(start = CoroutineStart.LAZY) {
println("job2 start")
println("job state isActive: $isActive [job2 in]")
delay(2000)
println("Coroutine 2")
}
println("job state isActive: ${job2.isActive}")
job2.join()
println("Coroutine 1")
}.join()
println("Main")
}
결과
1
2
3
4
5
6
job state isActive: false
job2 start
job state isActive: true [job2 in]
Coroutine 2
Coroutine 1
Main
Comments powered by Disqus.