Coroutine을 사용하다보면 단순히 비동기 작업을 실행하는 것보다 언제 끝나는지, 중간에 멈출 수 있는지, 다음 로직을 언제 실행해야 하는지가 더 중요해지는 순간이 옵니다.
이 때 핵심적으로 등장하는 개념이 join, cancel입니다. 이번 글에서는 join과 cancel을 중심으로 코루틴의 생명주기를 어떻게 제어하는지 정리해보고, 추가적으로 cancelAndJoin에 대해서도 알아보겠습니다.
join은 Job이 끝날 때까지 기다리는 suspend 함수입니다.
val job = launch {
delay(1000)
println("작업 끝")
}
job.join()
println("이 코드는 작업 이후 실행됨")
위의 코드 블럭을 실행해보면 job이 완전히 종료된 이후에 println이 실행됩니다. 즉, join은 이 작업이 끝난 이후에만 다음 로직을 실행하고 싶다는 의도를 명확하게 표현합니다. join은 작업 순서를 보장해야할 때, 결과는 필요없고 종료 시점만 중요할 때, 여러 Job의 종료를 기다릴 때 사용합니다.
await와 비슷해보이지만, await는 결과 값을 사용하는 로직에 쓰이고, join은 겨로가와 상관없이 작업 완료 시점만 보장하고 싶을 때 사용합니다.
cancel은 코루틴을 취소 상태로 전환시키는 함수입니다. 중요한 점은 즉시 종료가 아니라, 취소 요청이라는 것입니다.
val job = launch {
repeat(5) {
delay(500)
println("작업 중 $it")
}
}
delay(1200)
job.cancel()
println("cancel 호출")
while (isActive) {
// 안전한 취소 포인트
}
cancel은 더 이상 필요없는 작업을 중단해야할 때, 화면전환이나 스코프 종료, 타임아웃 처리, 리소스 낭비를 막고 싶을 때 주로 사용합니다.
Cancel과 Join을 하나로 합친 cancelAndJoin도 있습니다.
job.cancelAndJoin()
이 한 줄은 다음을 의미합니다.
즉, 이 코루틴은 이제 필요없고, 완전히 정리된 이후 다음 단계로 넘어간다라는 의미입니다.
join과 cancel은 단순한 API가 아니라 코루틴의 생명주기를 명확하게 표현하는 도구입니다.
이 개념들을 명확히 구분해 사용하면, 코루틴 코드는 더 읽기 쉬워지고, 예측 가능하며, 안정적으로 동작하게 됩니다.