Kotlin Jobs
A Job is a handle to a coroutine that launch started. Code reads the state of the work through the handle and waits for the finish with join.
launch hands back a job
The job is read while its child still waits in delay(100), so isActive prints true. After join, the finished job reads isCompleted true and isActive false.
import kotlinx.coroutines.*
fun main() = runBlocking {
val job = launch {
delay(100)
println("child done")
}
println(job.isActive)
job.join()
println(job.isCompleted)
println(job.isActive)
println(job.isCancelled)
}join waits for the finish
The waiting line prints before main suspends at join. The child line can only print before the lines that follow join.
import kotlinx.coroutines.*
fun main() = runBlocking {
val job = launch {
delay(50)
println("work finished")
}
println("waiting")
job.join()
println("after join")
println(job.isCompleted)
}A job that has not finished yet
Both reads happen before main suspends, while the child still waits in its long delay. isCompleted reads false and isActive reads true at that point.
import kotlinx.coroutines.*
fun main() = runBlocking {
val job = launch {
delay(200)
println("slow work done")
}
println(job.isCompleted)
println(job.isActive)
job.join()
println(job.isCompleted)
}Two jobs joined in turn
The second job starts only after the first join returns. Each job is checked right after its own join.
import kotlinx.coroutines.*
fun main() = runBlocking {
val first = launch {
delay(30)
println("first done")
}
first.join()
println(first.isCompleted)
val second = launch {
println("second done")
}
second.join()
println(second.isCancelled)
}Example
import kotlinx.coroutines.*
fun main() = runBlocking {
val job = launch {
delay(80)
println("report ready")
}
println("active: ${job.isActive}")
job.join()
println("completed: ${job.isCompleted}")
println("cancelled: ${job.isCancelled}")
}Key points
- launch returns a Job value for the coroutine it starts.
- isActive reads true while the coroutine is still running.
- isCompleted reads true after the coroutine finishes.
- A job that finishes normally reads isCancelled as false.
- join waits for the coroutine to finish before the next line runs.
- A state read taken before any suspension point has a fixed value.
In this example, launch starts the report work and hands back its job. The active read runs before join suspends main, so it prints true. After join, the job reads completed true and cancelled false, because the work ended in the normal way.
Note
The Job handle stays readable after the work ends, so the final state can be checked.
Try it Yourself
Edit the code, then press Run.
Running is simulated ยท Kotlin Playground
Exercise
After job.join() returns for a launch job that finished normally, what does job.isCompleted read?