0
# Jobs and Deferreds
1
2
Lifecycle management for coroutines including cancellation, completion tracking, and result handling. These interfaces provide the foundation for structured concurrency and coroutine coordination.
3
4
## Capabilities
5
6
### Job Interface
7
8
The fundamental interface representing a cancellable background task with a well-defined lifecycle.
9
10
```kotlin { .api }
11
/**
12
* A background job. Conceptually, a job is a cancellable thing with a lifecycle
13
* that concludes in its completion.
14
*/
15
interface Job : CoroutineContext.Element {
16
/**
17
* Returns true when this job is active -- it was already started and has not
18
* completed nor was cancelled yet.
19
*/
20
val isActive: Boolean
21
22
/**
23
* Returns true when this job has completed for any reason.
24
*/
25
val isCompleted: Boolean
26
27
/**
28
* Returns true if this job was cancelled. A job becomes cancelled when it
29
* finishes with a CancellationException.
30
*/
31
val isCancelled: Boolean
32
33
/**
34
* Returns a sequence of this job's children.
35
*/
36
val children: Sequence<Job>
37
38
/**
39
* Starts this job if it was created with CoroutineStart.LAZY.
40
* Returns true if job was started by this call, false if it was already started.
41
*/
42
fun start(): Boolean
43
44
/**
45
* Cancels this job with an optional cancellation cause.
46
* A cause can be used to specify an error message or to provide other details.
47
*/
48
fun cancel(cause: CancellationException? = null)
49
50
/**
51
* Suspends current coroutine until this job is complete.
52
*/
53
suspend fun join()
54
55
/**
56
* Registers a completion handler for this job.
57
*/
58
fun invokeOnCompletion(handler: CompletionHandler): DisposableHandle
59
60
/**
61
* Registers a completion handler for this job.
62
*/
63
fun invokeOnCompletion(
64
onCancelling: Boolean = false,
65
invokeImmediately: Boolean = true,
66
handler: CompletionHandler
67
): DisposableHandle
68
}
69
70
/**
71
* Handler for Job completion.
72
*/
73
typealias CompletionHandler = (cause: Throwable?) -> Unit
74
75
/**
76
* Represents a disposable resource that can be disposed/cancelled.
77
*/
78
interface DisposableHandle {
79
fun dispose()
80
}
81
```
82
83
**Usage Examples:**
84
85
```kotlin
86
import kotlinx.coroutines.*
87
88
val scope = MainScope()
89
90
// Basic job lifecycle management
91
val job = scope.launch {
92
repeat(10) { i ->
93
println("Working... $i")
94
delay(500)
95
}
96
}
97
98
// Check job status
99
println("Job is active: ${job.isActive}")
100
println("Job is completed: ${job.isCompleted}")
101
102
// Cancel the job
103
scope.launch {
104
delay(2000)
105
job.cancel()
106
println("Job cancelled")
107
}
108
109
// Wait for job completion
110
scope.launch {
111
job.join()
112
println("Job finished")
113
}
114
115
// Register completion handler
116
val disposable = job.invokeOnCompletion { cause ->
117
when (cause) {
118
null -> println("Job completed successfully")
119
is CancellationException -> println("Job was cancelled")
120
else -> println("Job failed with exception: $cause")
121
}
122
}
123
```
124
125
### Deferred Interface
126
127
A Job that produces a result value, representing a non-blocking cancellable future.
128
129
```kotlin { .api }
130
/**
131
* Deferred value is a non-blocking cancellable future — it is a Job with a result.
132
* It is created with the async coroutine builder.
133
*/
134
interface Deferred<out T> : Job {
135
/**
136
* Awaits for completion of this value without blocking the thread and returns
137
* the resulting value or throws the exception if the deferred was cancelled.
138
*/
139
suspend fun await(): T
140
141
/**
142
* Returns completed result or throws IllegalStateException if this deferred
143
* value has not completed yet.
144
*/
145
fun getCompleted(): T
146
147
/**
148
* Clause using the await suspending function as a select clause.
149
*/
150
val onAwait: SelectClause1<T>
151
}
152
```
153
154
**Usage Examples:**
155
156
```kotlin
157
import kotlinx.coroutines.*
158
159
val scope = MainScope()
160
161
// Basic deferred usage
162
val deferred = scope.async {
163
delay(1000)
164
"Hello World"
165
}
166
167
scope.launch {
168
try {
169
val result = deferred.await()
170
println("Result: $result")
171
} catch (e: CancellationException) {
172
println("Deferred was cancelled")
173
}
174
}
175
176
// Multiple deferreds
177
scope.launch {
178
val task1 = async { computeValue1() }
179
val task2 = async { computeValue2() }
180
val task3 = async { computeValue3() }
181
182
// Wait for all and collect results
183
val results = listOf(task1.await(), task2.await(), task3.await())
184
println("All results: $results")
185
}
186
187
// Non-blocking result access (only if completed)
188
val immediateDeferred = scope.async { 42 }
189
delay(100) // Ensure completion
190
if (immediateDeferred.isCompleted) {
191
val value = immediateDeferred.getCompleted()
192
println("Immediate result: $value")
193
}
194
```
195
196
### CompletableJob Interface
197
198
A Job that can be completed manually, providing explicit control over job lifecycle.
199
200
```kotlin { .api }
201
/**
202
* A Job that can be completed using CompletableJob.complete() function.
203
* It is returned by Job() constructor function.
204
*/
205
interface CompletableJob : Job {
206
/**
207
* Completes this job. The result is true if this job was completed as
208
* a result of this invocation and false if it was already completed.
209
*/
210
fun complete(): Boolean
211
212
/**
213
* Completes this job exceptionally with the specified exception.
214
* The result is true if this job was completed as a result of this invocation
215
* and false if it was already completed.
216
*/
217
fun completeExceptionally(exception: Throwable): Boolean
218
}
219
220
/**
221
* Creates a job object in an active state.
222
* A failure of any child of this job immediately causes this job to fail too
223
* and cancels the rest of its children.
224
*/
225
fun Job(parent: Job? = null): CompletableJob
226
```
227
228
**Usage Examples:**
229
230
```kotlin
231
import kotlinx.coroutines.*
232
233
val scope = MainScope()
234
235
// Manual job completion
236
val completableJob = Job()
237
238
scope.launch {
239
try {
240
completableJob.join()
241
println("Job completed successfully!")
242
} catch (e: CancellationException) {
243
println("Job was cancelled")
244
}
245
}
246
247
// Complete the job manually after some work
248
scope.launch {
249
delay(1000)
250
// Do some work...
251
completableJob.complete()
252
}
253
254
// Job with parent-child relationship
255
val parentJob = Job()
256
val childJob = Job(parent = parentJob)
257
258
// If parent is cancelled, child is automatically cancelled
259
scope.launch {
260
delay(500)
261
parentJob.cancel()
262
// childJob is now also cancelled
263
}
264
265
// Exception completion
266
val jobWithException = Job()
267
scope.launch {
268
try {
269
jobWithException.join()
270
} catch (e: Exception) {
271
println("Job failed: ${e.message}")
272
}
273
}
274
275
scope.launch {
276
delay(1000)
277
jobWithException.completeExceptionally(RuntimeException("Something went wrong"))
278
}
279
```
280
281
### CompletableDeferred Interface
282
283
A Deferred that can be completed manually, combining the features of Deferred and CompletableJob.
284
285
```kotlin { .api }
286
/**
287
* A Deferred that can be completed via complete() and completeExceptionally() functions.
288
*/
289
interface CompletableDeferred<T> : Deferred<T>, CompletableJob {
290
/**
291
* Completes this deferred with a given value.
292
*/
293
fun complete(value: T): Boolean
294
295
/**
296
* Completes this deferred exceptionally with a given exception.
297
*/
298
override fun completeExceptionally(exception: Throwable): Boolean
299
}
300
301
/**
302
* Creates a CompletableDeferred in an active state.
303
*/
304
fun <T> CompletableDeferred(parent: Job? = null): CompletableDeferred<T>
305
```
306
307
**Usage Examples:**
308
309
```kotlin
310
import kotlinx.coroutines.*
311
312
val scope = MainScope()
313
314
// Manual deferred completion
315
val completableDeferred = CompletableDeferred<String>()
316
317
scope.launch {
318
try {
319
val result = completableDeferred.await()
320
println("Received result: $result")
321
} catch (e: Exception) {
322
println("Deferred failed: ${e.message}")
323
}
324
}
325
326
// Complete with value after some async work
327
scope.launch {
328
delay(1000)
329
val computedValue = "Computed result"
330
completableDeferred.complete(computedValue)
331
}
332
333
// Bridge callback-based APIs
334
fun fetchDataWithCallback(callback: (String?, Exception?) -> Unit) {
335
// Simulate async operation
336
scope.launch {
337
delay(500)
338
if (Math.random() > 0.5) {
339
callback("Success data", null)
340
} else {
341
callback(null, RuntimeException("Network error"))
342
}
343
}
344
}
345
346
suspend fun fetchDataSuspending(): String {
347
val deferred = CompletableDeferred<String>()
348
349
fetchDataWithCallback { data, error ->
350
if (error != null) {
351
deferred.completeExceptionally(error)
352
} else {
353
deferred.complete(data!!)
354
}
355
}
356
357
return deferred.await()
358
}
359
```
360
361
### SupervisorJob
362
363
A special job type that does not cancel other children when one child fails.
364
365
```kotlin { .api }
366
/**
367
* Creates a supervisor job object in an active state.
368
* Children of a supervisor job can fail independently of each other.
369
*/
370
fun SupervisorJob(parent: Job? = null): CompletableJob
371
```
372
373
**Usage Examples:**
374
375
```kotlin
376
import kotlinx.coroutines.*
377
378
val scope = MainScope()
379
380
// Regular job - child failure cancels siblings
381
val regularJob = Job()
382
val scopeWithRegularJob = CoroutineScope(regularJob + Dispatchers.Default)
383
384
scopeWithRegularJob.launch {
385
delay(2000)
386
println("Task 1 completed") // This won't print if task 2 fails
387
}
388
389
scopeWithRegularJob.launch {
390
delay(1000)
391
throw RuntimeException("Task 2 failed") // This cancels task 1
392
}
393
394
// Supervisor job - child failures are independent
395
val supervisorJob = SupervisorJob()
396
val scopeWithSupervisor = CoroutineScope(supervisorJob + Dispatchers.Default)
397
398
scopeWithSupervisor.launch {
399
delay(2000)
400
println("Task A completed") // This will print even if task B fails
401
}
402
403
scopeWithSupervisor.launch {
404
delay(1000)
405
throw RuntimeException("Task B failed") // This doesn't affect task A
406
}
407
408
// Handle individual failures in supervisor scope
409
scopeWithSupervisor.launch {
410
try {
411
riskyOperation()
412
} catch (e: Exception) {
413
println("Task failed but others continue: ${e.message}")
414
}
415
}
416
```
417
418
### Job State Management
419
420
Understanding job states and lifecycle transitions.
421
422
**Job States:**
423
424
| State | isActive | isCompleted | isCancelled |
425
|-------|----------|-------------|-------------|
426
| New (optional) | false | false | false |
427
| Active (default) | true | false | false |
428
| Completing | true | false | false |
429
| Cancelling | false | false | true |
430
| Cancelled | false | true | true |
431
| Completed | false | true | false |
432
433
**Usage Examples:**
434
435
```kotlin
436
import kotlinx.coroutines.*
437
438
val scope = MainScope()
439
440
// Monitor job state changes
441
val job = scope.launch(start = CoroutineStart.LAZY) {
442
println("Job started")
443
delay(1000)
444
println("Job work completed")
445
}
446
447
println("Initial state - Active: ${job.isActive}, Completed: ${job.isCompleted}, Cancelled: ${job.isCancelled}")
448
449
// Start the lazy job
450
job.start()
451
println("After start - Active: ${job.isActive}, Completed: ${job.isCompleted}, Cancelled: ${job.isCancelled}")
452
453
// Wait a bit then cancel
454
scope.launch {
455
delay(500)
456
job.cancel()
457
println("After cancel - Active: ${job.isActive}, Completed: ${job.isCompleted}, Cancelled: ${job.isCancelled}")
458
}
459
460
// Wait for completion
461
scope.launch {
462
job.join()
463
println("After join - Active: ${job.isActive}, Completed: ${job.isCompleted}, Cancelled: ${job.isCancelled}")
464
}
465
```