Coroutines support libraries for Kotlin providing structured concurrency primitives, Flow API for reactive streams, channels for communication, and synchronization utilities across all Kotlin platforms
—
Lifecycle management for coroutines including cancellation, completion tracking, and result handling. These interfaces provide the foundation for structured concurrency and coroutine coordination.
The fundamental interface representing a cancellable background task with a well-defined lifecycle.
/**
* A background job. Conceptually, a job is a cancellable thing with a lifecycle
* that concludes in its completion.
*/
interface Job : CoroutineContext.Element {
/**
* Returns true when this job is active -- it was already started and has not
* completed nor was cancelled yet.
*/
val isActive: Boolean
/**
* Returns true when this job has completed for any reason.
*/
val isCompleted: Boolean
/**
* Returns true if this job was cancelled. A job becomes cancelled when it
* finishes with a CancellationException.
*/
val isCancelled: Boolean
/**
* Returns a sequence of this job's children.
*/
val children: Sequence<Job>
/**
* Starts this job if it was created with CoroutineStart.LAZY.
* Returns true if job was started by this call, false if it was already started.
*/
fun start(): Boolean
/**
* Cancels this job with an optional cancellation cause.
* A cause can be used to specify an error message or to provide other details.
*/
fun cancel(cause: CancellationException? = null)
/**
* Suspends current coroutine until this job is complete.
*/
suspend fun join()
/**
* Registers a completion handler for this job.
*/
fun invokeOnCompletion(handler: CompletionHandler): DisposableHandle
/**
* Registers a completion handler for this job.
*/
fun invokeOnCompletion(
onCancelling: Boolean = false,
invokeImmediately: Boolean = true,
handler: CompletionHandler
): DisposableHandle
}
/**
* Handler for Job completion.
*/
typealias CompletionHandler = (cause: Throwable?) -> Unit
/**
* Represents a disposable resource that can be disposed/cancelled.
*/
interface DisposableHandle {
fun dispose()
}Usage Examples:
import kotlinx.coroutines.*
val scope = MainScope()
// Basic job lifecycle management
val job = scope.launch {
repeat(10) { i ->
println("Working... $i")
delay(500)
}
}
// Check job status
println("Job is active: ${job.isActive}")
println("Job is completed: ${job.isCompleted}")
// Cancel the job
scope.launch {
delay(2000)
job.cancel()
println("Job cancelled")
}
// Wait for job completion
scope.launch {
job.join()
println("Job finished")
}
// Register completion handler
val disposable = job.invokeOnCompletion { cause ->
when (cause) {
null -> println("Job completed successfully")
is CancellationException -> println("Job was cancelled")
else -> println("Job failed with exception: $cause")
}
}A Job that produces a result value, representing a non-blocking cancellable future.
/**
* Deferred value is a non-blocking cancellable future — it is a Job with a result.
* It is created with the async coroutine builder.
*/
interface Deferred<out T> : Job {
/**
* Awaits for completion of this value without blocking the thread and returns
* the resulting value or throws the exception if the deferred was cancelled.
*/
suspend fun await(): T
/**
* Returns completed result or throws IllegalStateException if this deferred
* value has not completed yet.
*/
fun getCompleted(): T
/**
* Clause using the await suspending function as a select clause.
*/
val onAwait: SelectClause1<T>
}Usage Examples:
import kotlinx.coroutines.*
val scope = MainScope()
// Basic deferred usage
val deferred = scope.async {
delay(1000)
"Hello World"
}
scope.launch {
try {
val result = deferred.await()
println("Result: $result")
} catch (e: CancellationException) {
println("Deferred was cancelled")
}
}
// Multiple deferreds
scope.launch {
val task1 = async { computeValue1() }
val task2 = async { computeValue2() }
val task3 = async { computeValue3() }
// Wait for all and collect results
val results = listOf(task1.await(), task2.await(), task3.await())
println("All results: $results")
}
// Non-blocking result access (only if completed)
val immediateDeferred = scope.async { 42 }
delay(100) // Ensure completion
if (immediateDeferred.isCompleted) {
val value = immediateDeferred.getCompleted()
println("Immediate result: $value")
}A Job that can be completed manually, providing explicit control over job lifecycle.
/**
* A Job that can be completed using CompletableJob.complete() function.
* It is returned by Job() constructor function.
*/
interface CompletableJob : Job {
/**
* Completes this job. The result is true if this job was completed as
* a result of this invocation and false if it was already completed.
*/
fun complete(): Boolean
/**
* Completes this job exceptionally with the specified exception.
* The result is true if this job was completed as a result of this invocation
* and false if it was already completed.
*/
fun completeExceptionally(exception: Throwable): Boolean
}
/**
* Creates a job object in an active state.
* A failure of any child of this job immediately causes this job to fail too
* and cancels the rest of its children.
*/
fun Job(parent: Job? = null): CompletableJobUsage Examples:
import kotlinx.coroutines.*
val scope = MainScope()
// Manual job completion
val completableJob = Job()
scope.launch {
try {
completableJob.join()
println("Job completed successfully!")
} catch (e: CancellationException) {
println("Job was cancelled")
}
}
// Complete the job manually after some work
scope.launch {
delay(1000)
// Do some work...
completableJob.complete()
}
// Job with parent-child relationship
val parentJob = Job()
val childJob = Job(parent = parentJob)
// If parent is cancelled, child is automatically cancelled
scope.launch {
delay(500)
parentJob.cancel()
// childJob is now also cancelled
}
// Exception completion
val jobWithException = Job()
scope.launch {
try {
jobWithException.join()
} catch (e: Exception) {
println("Job failed: ${e.message}")
}
}
scope.launch {
delay(1000)
jobWithException.completeExceptionally(RuntimeException("Something went wrong"))
}A Deferred that can be completed manually, combining the features of Deferred and CompletableJob.
/**
* A Deferred that can be completed via complete() and completeExceptionally() functions.
*/
interface CompletableDeferred<T> : Deferred<T>, CompletableJob {
/**
* Completes this deferred with a given value.
*/
fun complete(value: T): Boolean
/**
* Completes this deferred exceptionally with a given exception.
*/
override fun completeExceptionally(exception: Throwable): Boolean
}
/**
* Creates a CompletableDeferred in an active state.
*/
fun <T> CompletableDeferred(parent: Job? = null): CompletableDeferred<T>Usage Examples:
import kotlinx.coroutines.*
val scope = MainScope()
// Manual deferred completion
val completableDeferred = CompletableDeferred<String>()
scope.launch {
try {
val result = completableDeferred.await()
println("Received result: $result")
} catch (e: Exception) {
println("Deferred failed: ${e.message}")
}
}
// Complete with value after some async work
scope.launch {
delay(1000)
val computedValue = "Computed result"
completableDeferred.complete(computedValue)
}
// Bridge callback-based APIs
fun fetchDataWithCallback(callback: (String?, Exception?) -> Unit) {
// Simulate async operation
scope.launch {
delay(500)
if (Math.random() > 0.5) {
callback("Success data", null)
} else {
callback(null, RuntimeException("Network error"))
}
}
}
suspend fun fetchDataSuspending(): String {
val deferred = CompletableDeferred<String>()
fetchDataWithCallback { data, error ->
if (error != null) {
deferred.completeExceptionally(error)
} else {
deferred.complete(data!!)
}
}
return deferred.await()
}A special job type that does not cancel other children when one child fails.
/**
* Creates a supervisor job object in an active state.
* Children of a supervisor job can fail independently of each other.
*/
fun SupervisorJob(parent: Job? = null): CompletableJobUsage Examples:
import kotlinx.coroutines.*
val scope = MainScope()
// Regular job - child failure cancels siblings
val regularJob = Job()
val scopeWithRegularJob = CoroutineScope(regularJob + Dispatchers.Default)
scopeWithRegularJob.launch {
delay(2000)
println("Task 1 completed") // This won't print if task 2 fails
}
scopeWithRegularJob.launch {
delay(1000)
throw RuntimeException("Task 2 failed") // This cancels task 1
}
// Supervisor job - child failures are independent
val supervisorJob = SupervisorJob()
val scopeWithSupervisor = CoroutineScope(supervisorJob + Dispatchers.Default)
scopeWithSupervisor.launch {
delay(2000)
println("Task A completed") // This will print even if task B fails
}
scopeWithSupervisor.launch {
delay(1000)
throw RuntimeException("Task B failed") // This doesn't affect task A
}
// Handle individual failures in supervisor scope
scopeWithSupervisor.launch {
try {
riskyOperation()
} catch (e: Exception) {
println("Task failed but others continue: ${e.message}")
}
}Understanding job states and lifecycle transitions.
Job States:
| State | isActive | isCompleted | isCancelled |
|---|---|---|---|
| New (optional) | false | false | false |
| Active (default) | true | false | false |
| Completing | true | false | false |
| Cancelling | false | false | true |
| Cancelled | false | true | true |
| Completed | false | true | false |
Usage Examples:
import kotlinx.coroutines.*
val scope = MainScope()
// Monitor job state changes
val job = scope.launch(start = CoroutineStart.LAZY) {
println("Job started")
delay(1000)
println("Job work completed")
}
println("Initial state - Active: ${job.isActive}, Completed: ${job.isCompleted}, Cancelled: ${job.isCancelled}")
// Start the lazy job
job.start()
println("After start - Active: ${job.isActive}, Completed: ${job.isCompleted}, Cancelled: ${job.isCancelled}")
// Wait a bit then cancel
scope.launch {
delay(500)
job.cancel()
println("After cancel - Active: ${job.isActive}, Completed: ${job.isCompleted}, Cancelled: ${job.isCancelled}")
}
// Wait for completion
scope.launch {
job.join()
println("After join - Active: ${job.isActive}, Completed: ${job.isCompleted}, Cancelled: ${job.isCancelled}")
}Install with Tessl CLI
npx tessl i tessl/maven-org-jetbrains-kotlinx--kotlinx-coroutines-core