fun main(): Unit = runBlocking {
val job1 = CoroutineScope(Dispatchers.Default).launch {
// 새로운 루트 코루틴
// ...
}
val job2 = CoroutineScope(Dispatchers.Default).launch {
// ...
}
// 부모 스레드 종료되지 않도록
delay(1000L)
}
launch
에서는 내부에서 Exception 을 던질 경우, 예외가 즉시 상위 코루틴에 잔파됨async
에서는 내부에서 Exception 을 던져도, 예외가 발생하지 않음
async.await()
하는 시점에 예외가 터짐launch
, async
모두 CoroutineStart.LAZY
상태라면 start
해야 예외가 qkftodgkafun main(): Unit = runBlocking {
val job1 = CoroutineScope(Dispatchers.Default).launch {
throw IllegalArgumentException() // 이건 바로 터짐
}
val job2 = CoroutineScope(Dispatchers.Default).async {
throw IllegalArgumentException()
}
delay(1000L)
job2.await() // 얘는 여기서 터짐
}
async
를 발생시켰지만 예외가 즉시 발생
fun main(): Unit = runBlocking {
val job2 = async {
throw IllegalArgumentException()
}
delay(1000L)
job2.await() // 여기서 터짐
}
SupervisorJob()
fun main(): Unit = runBlocking {
val job = async(SupervisorJob()) {
throw IllegalArgumentException()
}
}
try - catch - finally
CoroutineExceptionHandler
try - catch - finally
와 다르게 예외 발생 이후 에러 로깅 / 에러 메시지 전송 등에 활용val exceptionHandler = CoroutineExceptionHandler {
context, // 코루틴 구성 요소
throwable -> println("Exception") // 발생한 예외 처리
}
fun main(): Unit = runBlocking {
val exceptionHandler = CoroutineExceptionHandler { _, _ ->
println("Exception")
}
// try-catch 없어도 예외를 처리할 수 있음
val job = CoroutineScope(Displathers.Default).launch(exceptionHandler) {
throw IllegalArgumentException()
}
}
CoroutineExceptionHandler 주의 사항
-
launch
에만 적용 가능하고, 부모 코루틴이 있으면 동작하지 않음
- 루트(최상단) 코루틴에서 공통 에러 처리에 사용할 수 있을 듯?
CancellationException
을 던지는데, 일반적인 예외와의 차이점?
CancellationException
인 경우 취소로 간주하고 부모 코루틴에게 전파되지 않음
- 루트 코루틴: 가장 상위에 있는 코루틴으로, 새로운
CoroutineScope
를 사용하여 생성된다. 루트 코루틴은 상위 코루틴이 없기 때문에 예외가 전파되지 않는다.- SupervisorJob: 자식 코루틴의 실패가 부모 코루틴에 영향을 미치지 않도록 하는 특별한 Job. 예외가 발생해도 다른 자식 코루틴들은 영향을 받지 않으며, 부모 코루틴도 취소되지 않는다.
- CoroutineExceptionHandler의 한계:
CoroutineExceptionHandler
는launch
코루틴 빌더에서만 사용할 수 있으며,async
와 함께 사용할 수 없다. 이는async
의 결과를Deferred
를 통해 처리하기 때문이다. 예외 처리를 위해async
에서는try-catch
를 사용해야 한다.