Sometimes we need to close some thread, and we can't just kill the thread as we need to free resources and close connections.
Coroutines provide a simple undo mechanism to solve such problems and problems with long-running operations or memory leaks.
Let's create an object using the Job()
factory function:
suspend fun main() = coroutineScope {
val job = Job()
}
This Job object represents a running coroutine. Coroutines whose results we don't need can cancel anytime we want by calling the job.cancel()
function:
suspend fun main() = coroutineScope {
val job = Job()
launch(job) {
repeat(1000) { i ->
delay(50)
println("$i")
}
}
job.cancel()
}
The coroutine will be canceled without waiting for its actual completion. Calling cancel again does nothing.
The cancellation of a coroutine is fully thread-safe and non-blocking.
If we need to wait for the Job to be complete, we can use the job.join()
:
suspend fun main() = coroutineScope {
val job = Job()
launch(job) {
repeat(1000) { i ->
delay(50)
println("$i")
}
}
delay(500)
job.cancel()
job.join()
println("Cancelled")
}
We can also combine these two calls into the job.cancelAndJoin()
function.
If the job is canceled, a CancellationException
will be thrown. We can catch it with try-catch-finally:
suspend fun main() = coroutineScope {
val job = Job()
launch(job) {
try {
repeat(1000) { i ->
delay(50)
println("$i")
}
} catch (e: CancellationException) {
println(e)
} finally {
println("Finally")
}
}
delay(500)
job.cancelAndJoin()
println("Cancelled")
}
СancelationException
is a special exception to handle coroutine execution cancellation.
We can define behavior for all unhandled exceptions that occur in the current coroutine execution context. To do this, you can use CoroutineExceptionHandler
, which is an interceptor for any exception.
CoroutineExceptionHandler { coroutineContext, throwable ->
println(throwable)
}
We can catch an exception this way from any thread and define default behavior for all of them. CoroutineExceptionHandler
is called last after an error has occurred.
Cancellation in coroutines is easy to use and is important for the performance of your application. We can use cancellation in coroutines for easy resource cleaning or possibly some form of error logging.