Coroutines always execute in some context represented by a value of the type, defined in the Kotlin standard library.

    The coroutine context is a set of various elements. The main elements are the Job of the coroutine, which we’ve seen before, and its dispatcher, which is covered in this section.

    The coroutine context includes a coroutine dispatcher (see ) that determines what thread or threads the corresponding coroutine uses for its execution. The coroutine dispatcher can confine coroutine execution to a specific thread, dispatch it to a thread pool, or let it run unconfined.

    All coroutine builders like launch and accept an optional CoroutineContext parameter that can be used to explicitly specify the dispatcher for the new coroutine and other context elements.

    Try the following example:

    It produces the following output (maybe in different order):

    1. Default : I'm working in thread DefaultDispatcher-worker-1
    2. newSingleThreadContext: I'm working in thread MyOwnThread
    3. main runBlocking : I'm working in thread main

    When launch { ... } is used without parameters, it inherits the context (and thus dispatcher) from the it is being launched from. In this case, it inherits the context of the main runBlocking coroutine which runs in the main thread.

    Dispatchers.Unconfined is a special dispatcher that also appears to run in the main thread, but it is, in fact, a different mechanism that is explained later.

    The default dispatcher that is used when coroutines are launched in is represented by Dispatchers.Default and uses a shared background pool of threads, so launch(Dispatchers.Default) { ... } uses the same dispatcher as GlobalScope.launch { ... }.

    creates a thread for the coroutine to run. A dedicated thread is a very expensive resource. In a real application it must be either released, when no longer needed, using the close function, or stored in a top-level variable and reused throughout the application.

    Unconfined vs confined dispatcher

    The Dispatchers.Unconfined coroutine dispatcher starts a coroutine in the caller thread, but only until the first suspension point. After suspension it resumes the coroutine in the thread that is fully determined by the suspending function that was invoked. The unconfined dispatcher is appropriate for coroutines which neither consume CPU time nor update any shared data (like UI) confined to a specific thread.

    On the other side, the dispatcher is inherited from the outer by default. The default dispatcher for the runBlocking coroutine, in particular, is confined to the invoker thread, so inheriting it has the effect of confining execution to this thread with predictable FIFO scheduling.

    1. import kotlinx.coroutines.*
    2. fun main() = runBlocking<Unit> {
    3. //sampleStart
    4. launch(Dispatchers.Unconfined) { // not confined -- will work with main thread
    5. println("Unconfined : I'm working in thread ${Thread.currentThread().name}")
    6. delay(500)
    7. println("Unconfined : After delay in thread ${Thread.currentThread().name}")
    8. }
    9. launch { // context of the parent, main runBlocking coroutine
    10. println("main runBlocking: I'm working in thread ${Thread.currentThread().name}")
    11. delay(1000)
    12. println("main runBlocking: After delay in thread ${Thread.currentThread().name}")
    13. }
    14. //sampleEnd
    15. }

    You can get the full code .

    Produces the output:

    1. Unconfined : I'm working in thread main
    2. main runBlocking: I'm working in thread main
    3. Unconfined : After delay in thread kotlinx.coroutines.DefaultExecutor
    4. main runBlocking: After delay in thread main

    So, the coroutine with the context inherited from runBlocking {...} continues to execute in the main thread, while the unconfined one resumes in the default executor thread that the delay function is using.

    The unconfined dispatcher is an advanced mechanism that can be helpful in certain corner cases where dispatching of a coroutine for its execution later is not needed or produces undesirable side-effects, because some operation in a coroutine must be performed right away. The unconfined dispatcher should not be used in general code.

    Debugging coroutines and threads

    Coroutines can suspend on one thread and resume on another thread. Even with a single-threaded dispatcher it might be hard to figure out what the coroutine was doing, where, and when if you don’t have special tooling.

    Debugging with IDEA

    The Coroutine Debugger of the Kotlin plugin simplifies debugging coroutines in IntelliJ IDEA.

    Debugging works for versions 1.3.8 or later of kotlinx-coroutines-core.

    The Debug tool window contains the Coroutines tab. In this tab, you can find information about both currently running and suspended coroutines. The coroutines are grouped by the dispatcher they are running on.

    • Check the state of each coroutine.
    • See the values of local and captured variables for both running and suspended coroutines.
    • See a full coroutine creation stack, as well as a call stack inside the coroutine. The stack includes all frames with variable values, even those that would be lost during standard debugging.
    • Get a full report that contains the state of each coroutine and its stack. To obtain it, right-click inside the Coroutines tab, and then click Get Coroutines Dump.

    To start coroutine debugging, you just need to set breakpoints and run the application in debug mode.

    Learn more about coroutines debugging in the .

    Debugging using logging

    Another approach to debugging applications with threads without Coroutine Debugger is to print the thread name in the log file on each log statement. This feature is universally supported by logging frameworks. When using coroutines, the thread name alone does not give much of a context, so kotlinx.coroutines includes debugging facilities to make it easier.

    Run the following code with -Dkotlinx.coroutines.debug JVM option:

    1. import kotlinx.coroutines.*
    2. fun log(msg: String) = println("[${Thread.currentThread().name}] $msg")
    3. fun main() = runBlocking<Unit> {
    4. //sampleStart
    5. val a = async {
    6. log("I'm computing a piece of the answer")
    7. 6
    8. }
    9. val b = async {
    10. log("I'm computing another piece of the answer")
    11. 7
    12. }
    13. log("The answer is ${a.await() * b.await()}")
    14. //sampleEnd
    15. }

    You can get the full code .

    There are three coroutines. The main coroutine (#1) inside runBlocking and two coroutines computing the deferred values a (#2) and b (#3). They are all executing in the context of runBlocking and are confined to the main thread. The output of this code is:

    1. [main @coroutine#2] I'm computing a piece of the answer
    2. [main @coroutine#3] I'm computing another piece of the answer
    3. [main @coroutine#1] The answer is 42

    The log function prints the name of the thread in square brackets, and you can see that it is the main thread with the identifier of the currently executing coroutine appended to it. This identifier is consecutively assigned to all created coroutines when the debugging mode is on.

    Run the following code with the -Dkotlinx.coroutines.debug JVM option (see debug):

    1. import kotlinx.coroutines.*
    2. fun log(msg: String) = println("[${Thread.currentThread().name}] $msg")
    3. fun main() {
    4. //sampleStart
    5. newSingleThreadContext("Ctx1").use { ctx1 ->
    6. newSingleThreadContext("Ctx2").use { ctx2 ->
    7. log("Started in ctx1")
    8. withContext(ctx2) {
    9. log("Working in ctx2")
    10. }
    11. log("Back to ctx1")
    12. }
    13. }
    14. }
    15. //sampleEnd
    16. }

    You can get the full code .

    It demonstrates several new techniques. One is using runBlocking with an explicitly specified context, and the other one is using the function to change the context of a coroutine while still staying in the same coroutine, as you can see in the output below:

    1. [Ctx1 @coroutine#1] Started in ctx1
    2. [Ctx2 @coroutine#1] Working in ctx2
    3. [Ctx1 @coroutine#1] Back to ctx1

    Note that this example also uses the use function from the Kotlin standard library to release threads created with newSingleThreadContext when they are no longer needed.

    Job in the context

    The coroutine’s Job is part of its context, and can be retrieved from it using the expression:

    You can get the full code .

    In the debug mode, it outputs something like this:

    1. My job is "coroutine#1":BlockingCoroutine{Active}@6d311334

    Note that in CoroutineScope is just a convenient shortcut for coroutineContext[Job]?.isActive == true.

    Children of a coroutine

    When a coroutine is launched in the CoroutineScope of another coroutine, it inherits its context via and the Job of the new coroutine becomes a child of the parent coroutine’s job. When the parent coroutine is cancelled, all its children are recursively cancelled, too.

    However, when is used to launch a coroutine, there is no parent for the job of the new coroutine. It is therefore not tied to the scope it was launched from and operates independently.

    1. import kotlinx.coroutines.*
    2. fun main() = runBlocking<Unit> {
    3. //sampleStart
    4. // launch a coroutine to process some kind of incoming request
    5. val request = launch {
    6. // it spawns two other jobs, one with GlobalScope
    7. GlobalScope.launch {
    8. println("job1: I run in GlobalScope and execute independently!")
    9. delay(1000)
    10. println("job1: I am not affected by cancellation of the request")
    11. }
    12. // and the other inherits the parent context
    13. launch {
    14. delay(100)
    15. println("job2: I am a child of the request coroutine")
    16. delay(1000)
    17. println("job2: I will not execute this line if my parent request is cancelled")
    18. }
    19. }
    20. delay(500)
    21. request.cancel() // cancel processing of the request
    22. delay(1000) // delay a second to see what happens
    23. println("main: Who has survived request cancellation?")
    24. //sampleEnd
    25. }

    You can get the full code here.

    The output of this code is:

    1. job1: I run in GlobalScope and execute independently!
    2. job2: I am a child of the request coroutine
    3. job1: I am not affected by cancellation of the request
    4. main: Who has survived request cancellation?

    A parent coroutine always waits for completion of all its children. A parent does not have to explicitly track all the children it launches, and it does not have to use to wait for them at the end:

    1. import kotlinx.coroutines.*
    2. fun main() = runBlocking<Unit> {
    3. //sampleStart
    4. // launch a coroutine to process some kind of incoming request
    5. val request = launch {
    6. repeat(3) { i -> // launch a few children jobs
    7. launch {
    8. delay((i + 1) * 200L) // variable delay 200ms, 400ms, 600ms
    9. println("Coroutine $i is done")
    10. }
    11. }
    12. println("request: I'm done and I don't explicitly join my children that are still active")
    13. }
    14. request.join() // wait for completion of the request, including all its children
    15. println("Now processing of the request is complete")
    16. //sampleEnd
    17. }

    You can get the full code here.

    1. request: I'm done and I don't explicitly join my children that are still active
    2. Coroutine 0 is done
    3. Coroutine 1 is done
    4. Coroutine 2 is done
    5. Now processing of the request is complete

    Naming coroutines for debugging

    Automatically assigned ids are good when coroutines log often and you just need to correlate log records coming from the same coroutine. However, when a coroutine is tied to the processing of a specific request or doing some specific background task, it is better to name it explicitly for debugging purposes. The CoroutineName context element serves the same purpose as the thread name. It is included in the thread name that is executing this coroutine when the is turned on.

    The following example demonstrates this concept:

    1. import kotlinx.coroutines.*
    2. fun log(msg: String) = println("[${Thread.currentThread().name}] $msg")
    3. fun main() = runBlocking(CoroutineName("main")) {
    4. //sampleStart
    5. log("Started main coroutine")
    6. // run two background value computations
    7. val v1 = async(CoroutineName("v1coroutine")) {
    8. delay(500)
    9. log("Computing v1")
    10. 252
    11. }
    12. val v2 = async(CoroutineName("v2coroutine")) {
    13. delay(1000)
    14. log("Computing v2")
    15. }
    16. log("The answer for v1 / v2 = ${v1.await() / v2.await()}")
    17. //sampleEnd
    18. }

    The output it produces with -Dkotlinx.coroutines.debug JVM option is similar to:

    1. [main @main#1] Started main coroutine
    2. [main @v1coroutine#2] Computing v1
    3. [main @v2coroutine#3] Computing v2
    4. [main @main#1] The answer for v1 / v2 = 42

    Combining context elements

    Sometimes we need to define multiple elements for a coroutine context. We can use the + operator for that. For example, we can launch a coroutine with an explicitly specified dispatcher and an explicitly specified name at the same time:

    You can get the full code .

    The output of this code with the -Dkotlinx.coroutines.debug JVM option is:

    1. I'm working in thread DefaultDispatcher-worker-1 @test#2

    Let us put our knowledge about contexts, children and jobs together. Assume that our application has an object with a lifecycle, but that object is not a coroutine. For example, we are writing an Android application and launch various coroutines in the context of an Android activity to perform asynchronous operations to fetch and update data, do animations, etc. All of these coroutines must be cancelled when the activity is destroyed to avoid memory leaks. We, of course, can manipulate contexts and jobs manually to tie the lifecycles of the activity and its coroutines, but kotlinx.coroutines provides an abstraction encapsulating that: CoroutineScope. You should be already familiar with the coroutine scope as all coroutine builders are declared as extensions on it.

    We manage the lifecycles of our coroutines by creating an instance of tied to the lifecycle of our activity. A instance can be created by the CoroutineScope() or factory functions. The former creates a general-purpose scope, while the latter creates a scope for UI applications and uses Dispatchers.Main as the default dispatcher:

    1. class Activity {
    2. private val mainScope = MainScope()
    3. fun destroy() {
    4. mainScope.cancel()
    5. }
    6. // to be continued ...

    Now, we can launch coroutines in the scope of this Activity using the defined scope. For the demo, we launch ten coroutines that delay for a different time:

    1. // class Activity continues
    2. fun doSomething() {
    3. // launch ten coroutines for a demo, each working for a different time
    4. repeat(10) { i ->
    5. mainScope.launch {
    6. delay((i + 1) * 200L) // variable delay 200ms, 400ms, ... etc
    7. println("Coroutine $i is done")
    8. }
    9. }
    10. }
    11. } // class Activity ends

    In our main function we create the activity, call our test doSomething function, and destroy the activity after 500ms. This cancels all the coroutines that were launched from doSomething. We can see that because after the destruction of the activity no more messages are printed, even if we wait a little longer.

    1. import kotlinx.coroutines.*
    2. class Activity {
    3. private val mainScope = CoroutineScope(Dispatchers.Default) // use Default for test purposes
    4. fun destroy() {
    5. mainScope.cancel()
    6. }
    7. fun doSomething() {
    8. // launch ten coroutines for a demo, each working for a different time
    9. repeat(10) { i ->
    10. mainScope.launch {
    11. delay((i + 1) * 200L) // variable delay 200ms, 400ms, ... etc
    12. println("Coroutine $i is done")
    13. }
    14. }
    15. }
    16. } // class Activity ends
    17. fun main() = runBlocking<Unit> {
    18. //sampleStart
    19. val activity = Activity()
    20. activity.doSomething() // run test function
    21. println("Launched coroutines")
    22. delay(500L) // delay for half a second
    23. println("Destroying activity!")
    24. activity.destroy() // cancels all coroutines
    25. delay(1000) // visually confirm that they don't work
    26. //sampleEnd
    27. }

    You can get the full code .

    The output of this example is:

    1. Launched coroutines
    2. Coroutine 0 is done
    3. Coroutine 1 is done
    4. Destroying activity!

    As you can see, only the first two coroutines print a message and the others are cancelled by a single invocation of job.cancel() in Activity.destroy().

    Note, that Android has first-party support for coroutine scope in all entities with the lifecycle. See the corresponding documentation.

    Thread-local data

    Sometimes it is convenient to have an ability to pass some thread-local data to or between coroutines. However, since they are not bound to any particular thread, this will likely lead to boilerplate if done manually.

    For ThreadLocal, the extension function is here for the rescue. It creates an additional context element which keeps the value of the given ThreadLocal and restores it every time the coroutine switches its context.

    It is easy to demonstrate it in action:

    1. import kotlinx.coroutines.*
    2. val threadLocal = ThreadLocal<String?>() // declare thread-local variable
    3. fun main() = runBlocking<Unit> {
    4. //sampleStart
    5. threadLocal.set("main")
    6. println("Pre-main, current thread: ${Thread.currentThread()}, thread local value: '${threadLocal.get()}'")
    7. val job = launch(Dispatchers.Default + threadLocal.asContextElement(value = "launch")) {
    8. println("Launch start, current thread: ${Thread.currentThread()}, thread local value: '${threadLocal.get()}'")
    9. yield()
    10. println("After yield, current thread: ${Thread.currentThread()}, thread local value: '${threadLocal.get()}'")
    11. }
    12. job.join()
    13. println("Post-main, current thread: ${Thread.currentThread()}, thread local value: '${threadLocal.get()}'")
    14. //sampleEnd
    15. }

    You can get the full code here.

    In this example we launch a new coroutine in a background thread pool using , so it works on a different thread from the thread pool, but it still has the value of the thread local variable that we specified using threadLocal.asContextElement(value = "launch"), no matter which thread the coroutine is executed on. Thus, the output (with debug) is:

    1. Pre-main, current thread: Thread[main @coroutine#1,5,main], thread local value: 'main'
    2. Launch start, current thread: Thread[DefaultDispatcher-worker-1 @coroutine#2,5,main], thread local value: 'launch'
    3. After yield, current thread: Thread[DefaultDispatcher-worker-2 @coroutine#2,5,main], thread local value: 'launch'
    4. Post-main, current thread: Thread[main @coroutine#1,5,main], thread local value: 'main'

    It’s easy to forget to set the corresponding context element. The thread-local variable accessed from the coroutine may then have an unexpected value, if the thread running the coroutine is different. To avoid such situations, it is recommended to use the method and fail-fast on improper usages.

    ThreadLocal has first-class support and can be used with any primitive kotlinx.coroutines provides. It has one key limitation, though: when a thread-local is mutated, a new value is not propagated to the coroutine caller (because a context element cannot track all object accesses), and the updated value is lost on the next suspension. Use withContext to update the value of the thread-local in a coroutine, see for more details.

    For advanced usage, for example for integration with logging MDC, transactional contexts or any other libraries which internally use thread-locals for passing data, see the documentation of the ThreadContextElement interface that should be implemented.