Coroutine — Job

A handled to coroutine

Hari Prasad
5 min readAug 17, 2023

Job — A handled to coroutine or piece of code.

A Job instance in the coroutineContext represents the coroutine itself.

A background job. Conceptually, a job is a cancellable thing with a life-cycle that culminates in its completion.

Create Job

When you launch a coroutine using a coroutine builder like launch, async, or runBlocking, it returns a reference to the coroutine job associated with that particular coroutine.

Life-Cycle

  • Job is created in the active state (it is created and started).
    — However, coroutine builders that provide an optional start parameter create a coroutine in the new state when this parameter is set to CoroutineStart.LAZY. Such a job can be made active by invoking start or join.
    — A job is active while the coroutine is working or until CompletableJob is completed, or until it fails or cancelled.
    — Failure of an active job with an exception makes it cancelling. A job can be cancelled at any time with cancel function that forces it to transition to the cancelling state immediately. The job becomes cancelled when it finishes executing its work and all its children complete.
    — Completion of an active coroutine’s body or a call to CompletableJob.complete transitions the job to the completing state. It waits in the completing state for all its children to complete before transitioning to the completed state. Note that completing state is purely internal to the job. For an outside observer a completing job is still active, while internally it is waiting for its children.
    — A coroutine job is said to complete exceptionally when its body throws an exception; a CompletableJob is completed exceptionally by calling CompletableJob.completeExceptionally. An exceptionally completed job is cancelled and the corresponding exception becomes the cancellation cause of the job.
    — Normal cancellation of a job is distinguished from its failure by the type of this exception that caused its cancellation. A coroutine that threw CancellationException is considered to be cancelled normally. If a cancellation cause is a different exception type, then the job is considered to have failed. When a job has failed, then its parent gets cancelled with the exception of the same type, thus ensuring transparency in delegating parts of the job to its children.
    — Note, that cancel function on a job only accepts CancellationException as a cancellation cause, thus calling cancel always results in a normal cancellation of a job, which does not lead to cancellation of its parent. This way, a parent can cancel its own children (cancelling all their children recursively, too) without cancelling itself.

Job States

  • isActive — Returns true when this job is active — it was already started and has not completed nor was cancelled yet. The job that is waiting for its children to complete is still considered to be active if it was not cancelled nor failed.
  • isCompleted — Returns true when this job has completed for any reason. A job that was cancelled or failed and has finished its execution is also considered complete. Job becomes complete only after all its children complete.
  • isCancelled — Returns true if this job was cancelled for any reason, either by explicit invocation of cancel or because it had failed or its child or parent was cancelled. In the general case, it does not imply that the job has already completed, because it may still be finishing whatever it was doing and waiting for its children to complete.
    See Job documentation for more details on cancellation and failures.

Hierarchy

  • Jobs have a hierarchy, So Jobs live in the hierarchy of other Jobs
  • Jobs can be arranged into parent-child hierarchies
    where cancellation of a parent leads to immediate cancellation of all its children recursively.
    — Failure of a child with an exception other than CancellationException immediately cancels its parent and, consequently, all its other children. This behavior can be customized using SupervisorJob.

Operations on Job

  • Jobs allow us to manipulate the coroutine lifecycle
  • start()
    — returns true if this invocation actually started the coroutine
    — false if it was already started or completed
  • join()
    to make wait for the completion of Job or Coroutines before proceeding with the main thread
  • cancel() — to cancel a coroutine job
  • cancelAndJoin()
  • invokeOnCompletion()
import kotlinx.coroutines.*

fun main() = runBlocking {
val job1 = GlobalScope.launch {
repeat(5) {
delay(500)
println("Job 1: Working $it")
}
println("Job 1: Done")
}

val job2 = GlobalScope.launch {
repeat(5) {
delay(300)
println("Job 2: Working $it")
}
println("Job 2: Done")
}

println("Main thread: Waiting for jobs to complete")

// Wait for both jobs to finish
job1.join()
job2.join()

println("Main thread: All jobs are done")
}
import kotlinx.coroutines.*

fun main() = runBlocking {
val job = launch {
repeat(10) { i ->
println("Working $i")
delay(500)
}
}

delay(1500) // Allow the coroutine to run for a while

println("Main thread: Canceling coroutine job")
job.cancel()

job.join() // Wait for the coroutine to complete or be canceled
println("Main thread: Coroutine job is done")
}

Types of Jobs

  • Job
    — The basic job type returned by coroutine builders like launch, async, and runBlocking. It represents a single coroutine and provides control over its lifecycle, such as starting, waiting, and cancelling. It can be used for simple asynchronous tasks.
  • Deferred
    — A specialization of the Job type returned by the async coroutine builder. It represents a coroutine that produces a result of type T and provides a way to await the result using the await function. Deferred is used when you need to perform computations concurrently and asynchronously and obtain a result when it's ready.
  • SupervisorJob
    — A job type that is used as a parent job for child coroutines. Unlike regular jobs, a failure or cancellation of a child coroutine does not propagate to its parent and other siblings. It’s useful when you want to isolate failures in a specific branch of coroutines.
  • CompletableJob
    — A type of job that can be completed explicitly using the complete() function. It's often used in custom implementations or when you want to create custom ways of handling the job's lifecycle.

--

--