【Coroutinesガイド】コルーチンコンテキストとディスパッチャー

※ソース記事は[こちら](https://kotlinlang.org/docs/coroutine-context-and-dispatchers.html)
コルーチンはKotlin標準ライブラリで定義されている[CoroutineContext](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.coroutines/-coroutine-context/)型の値によって表されるいくつかのコンテキスト内で常に実行する。
コルーチンコンテキストは、様々な要素のセットである。主な要素は、以前に見てきたコルーチンの[Job](https://kotlinlang.org/api/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-job/index.html)と、このセクションでカバーするディスパッチャーである。
## ディスパッチャーとスレッド
コルーチンコンテキストには、対応するコルーチンが実行するために使う、スレッドあるいはスレッド群を決定するコルーチンディスパッチャー([CoroutineDispatcher](https://kotlinlang.org/api/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-dispatcher/index.html)を参照)が含まれている。コルーチンディスパッチャーはコルーチンの実行を特定のスレッドに制限したり、スレッドプールにディスパッチしたり、制限せずに実行させることができる。
[launch](https://kotlinlang.org/api/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/launch.html)と[async](https://kotlinlang.org/api/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/async.html)のようなすべてのコルーチンビルダーは、オプションの[CoroutineContext](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.coroutines/-coroutine-context/)パラメータを持ち、新しいコルーチンと他のコンテキスト要素のためにディスパッチャーを明示して使うことができる。
次の例を試してみよう。
```Kotlin
import kotlinx.coroutines.*

fun main() = runBlocking<Unit> {
    launch { // 親のコンテキスト、main runBlockingコルーチン
        println("main runBlocking      : I'm working in thread ${Thread.currentThread().name}")
    }
    launch(Dispatchers.Unconfined) { // 制限なし -- メインスレッドで動作する
        println("Unconfined            : I'm working in thread ${Thread.currentThread().name}")
    }
    launch(Dispatchers.Default) { // DefaultDispatcherにディスパッチされる
        println("Default               : I'm working in thread ${Thread.currentThread().name}")
    }
    launch(newSingleThreadContext("MyOwnThread")) { // 自身の新スレッドを得る
        println("newSingleThreadContext: I'm working in thread ${Thread.currentThread().name}")
    }    
}
```
これは次の出力を生成する。(異なる順序かもしれない)
```
Unconfined            : I'm working in thread main
Default               : I'm working in thread DefaultDispatcher-worker-1
newSingleThreadContext: I'm working in thread MyOwnThread
main runBlocking      : I'm working in thread main
```
`launch { ... }`は、パラメータ無しで使うとき、起動元である[CoroutineScope](https://kotlinlang.org/api/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-scope/index.html)からコンテキスト(したがってディスパッチャも)を継承する。このケースでは、`main`スレッドで動作するメインの`runBlocking`コルーチンのコンテキストを継承している。
[Dispatchers.Unconfined](https://kotlinlang.org/api/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-dispatchers/-unconfined.html)も、`main`スレッドで実行するように見えるが、実際は後で説明する別のメカニズムで動作する特別なディスパッチャである。
デフォルトディスパッチャーは、他のディスパッチャーがスコープで明示的に指定されてないときに使われる。それは`Dispatchers.Default`で表され、共有のバックグラウンドスレッドプールを使用する。
[newSingleThreadContext](https://kotlinlang.org/api/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/new-single-thread-context.html)は、実行するコルーチンのためにスレッドをつくる。専用のスレッドは大変高価なリソースである。実際のアプリケーションでは、それは不要になったら[close](https://kotlinlang.org/api/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-executor-coroutine-dispatcher/close.html)関数を使ってリリースされなければならない。あるいは、トップレベル変数に保存して、アプリケーション中で再利用する。
## 制限無しvs制限付きディスパッチャー
[Dispatchers.Unconfined](https://kotlinlang.org/api/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-dispatchers/-unconfined.html)のコルーチンディスパッチャーは、呼び出しスレッドでコルーチンを監視するが、それは最初の一時停止ポイントまでである。一時停止の後は、呼び出されたsuspend関数によって完全に決められたスレッドで復帰する。制限無しディスパッチャーは、CPUを消費せず、特定のスレッドで制限される共有データ(UIのような)を更新しないコルーチンに適している。
一方で、ディスパッチャーはデフォルトで外側の[CoroutineScope](https://kotlinlang.org/api/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-scope/index.html)から継承する。特に[runBlocking]()コルーチンのためのデフォルトディスパッチャーは、呼び出しスレッドに制限されており、それを継承することは、予測可能なFIFOスケジュールを持つこのスレッドに対する制限された実行の効果を持つ。
```Kotlin
import kotlinx.coroutines.*

fun main() = runBlocking<Unit> {
    launch(Dispatchers.Unconfined) { // 制限なし -- メインスレッドで動く
        println("Unconfined      : I'm working in thread ${Thread.currentThread().name}")
        delay(500)
        println("Unconfined      : After delay in thread ${Thread.currentThread().name}")
    }
    launch { // 親のコンテキスト、メインのrunBlockingコルーチン
        println("main runBlocking: I'm working in thread ${Thread.currentThread().name}")
        delay(1000)
        println("main runBlocking: After delay in thread ${Thread.currentThread().name}")
    }    
}
```
次の出力を生成する。
```
Unconfined      : I'm working in thread main
main runBlocking: I'm working in thread main
Unconfined      : After delay in thread kotlinx.coroutines.DefaultExecutor
main runBlocking: After delay in thread main
```
このように、`runBlocking {...}`から継承したコンテキストを持つコルーチンは、`main`スレッドで実行を続けるが、一方、制限無しのものは[delay](https://kotlinlang.org/api/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/delay.html)関数が使っているデフォルトの実行スレッドで復旧する。

::: note
制限無しのディスパッチャーは、コルーチン内のいくつかの操作がすぐに行われなければならないため、実行のためのコルーチンにディスパッチすることがのちに不要にであるか、望ましくない副作用を生むような、まれなケースで役に立つことがありうる。一般には制限無しのディスパッチャーは使うべきではない。
:::
## コルーチンとスレッドのデバッグ
コルーチンは、あるスレッドdで一時停止し、別のスレッドで再開することがある。シングルスレッドのディスパッチャーでさえ、コルーチンがどこでいつ何をしているのか、特別なツールが無いと、理解することが難しいかもしれない。
### IDEAを用いたデバッグ
Kotlinプラグインのコルーチンデバッガーは、IntelliJ IDEAにおいてコルーチンのデバッグを簡単にしてくれる。

::: note
デバッグは`kotlinx-coroutines-core`のバージョン1.3.8以降で動作する。
:::
**デバッグ**ツールウィンドウには**コルーチン**タブがある。このタブでは、現在実行中と一時停止中の両方のコルーチンについての情報を見つけることができる。コルーチンは実行しているディスパッチャーでグルーピングされている。
![scr1](https://kotlinlang.org/docs/images/coroutine-idea-debugging-1.png)
コルーチンデバッガーで次のことができる。
- それぞれのコルーチンの状態の確認
- 現在実行中と一時停止中の両方のコルーチンのローカル変数とキャプチャされた変数の値の参照
- コルーチン内部のコールスタックと同様に完全なコルーチンの生成スタックの参照。スタックには変数値を持つすべてのフレームが含まれ、標準のデバッグの間に失われてしまうものも含まれている。
- それぞれのコルーチンの状態とそのスタックを含む完全なレポート。取得するには、**コルーチン**タブの内部を右クリックして、その後、**コルーチンダンプの取得**をクリックする。

コルーチンのデバッグを開始するには、ブレークポイントをセットし、デバッグモードでアプリケーションを実行するだけである。
[チュートリアル](https://kotlinlang.org/docs/tutorials/coroutines/debug-coroutines-with-idea.html)でコルーチンのデバッグについての知識を深める。
### ログを用いたデバッグ
コルーチンデバッガー抜きでスレッドを用いたアプリケーションをデバッグする、別のアプローチは、それぞれのログステートメントでログファイルにスレッド名を出力することである。この機能はロギングフレームワークで広くサポートされている。コルーチンを使うとき、スレッド名だけではコンテキストの多くが提供されないので、`kotlinx.coroutines`にはそれを簡単にするためのデバッグ機能が含まれている。
次のコードを`-Dkotlinx.coroutines.debug`JVMオプションをつけて実行する。
```Kotlin
import kotlinx.coroutines.*

fun log(msg: String) = println("[${Thread.currentThread().name}] $msg")

fun main() = runBlocking<Unit> {
    val a = async {
        log("I'm computing a piece of the answer")
        6
    }
    val b = async {
        log("I'm computing another piece of the answer")
        7
    }
    log("The answer is ${a.await() * b.await()}")    
}
```
3つのコルーチンがある。メインコルーチン(#1)は`runBlocking`の内部であり、二つのコルーチンはdeferred値の`a`(#2)と`b`(#3)を計算している。それらはすべて`runBlocking`のコンテキストで実行され、メインスレッドで制限されている。このコードの出力は以下のとおり。
```
[main @coroutine#2] I'm computing a piece of the answer
[main @coroutine#3] I'm computing another piece of the answer
[main @coroutine#1] The answer is 42
```
ログ関数はスレッド名を大括弧内に出力し、現在実行しているコルーチンに追加された識別子を持つ`main`スレッドが確認できる。この識別子はデバッグモードがオンの間は、結果的にすべての生成されたコルーチンに割り当てられる。

::: note
デバッグモードはJVMが`-ea`オプションをつけて実行するときもオンになる。[DEBUG_PROPERTY_NAME](https://kotlinlang.org/api/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-d-e-b-u-g_-p-r-o-p-e-r-t-y_-n-a-m-e.html)プロパティのドキュメント内で、デバッグ機能について続きを読むことができる。
:::
### スレッド間のジャンプ
次のコードを`-Dkotlinx.coroutines.debug`JVMオプションつきで実行する。([debug](https://kotlinlang.org/docs/coroutine-context-and-dispatchers.html#debugging-coroutines-and-threads)を参照)
```Kotlin
import kotlinx.coroutines.*

fun log(msg: String) = println("[${Thread.currentThread().name}] $msg")

fun main() {
    newSingleThreadContext("Ctx1").use { ctx1 ->
        newSingleThreadContext("Ctx2").use { ctx2 ->
            runBlocking(ctx1) {
                log("Started in ctx1")
                withContext(ctx2) {
                    log("Working in ctx2")
                }
                log("Back to ctx1")
            }
        }
    }    
}
```
いくつかの新しいテクニックを示している。一つは明示したコンテキストを持つ[runBlocking](https://kotlinlang.org/api/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/run-blocking.html)を使うもので、もうひとつは、[withContext]()を使い、まだ同じコルーチンにとどまっている間にコルーチンのコンテキストを変更するものである。
以下の出力を見ることができる。
```
[Ctx1 @coroutine#1] Started in ctx1
[Ctx2 @coroutine#1] Working in ctx2
[Ctx1 @coroutine#1] Back to ctx1
```
留意すべきは、この例ではもう不要であるときに、[newSingleThreadContext](https://kotlinlang.org/api/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/new-single-thread-context.html)で作られたスレッドを解放するため、Kotlin標準ライブラリから`use`関数を使っている。
## コンテキストのジョブ
コルーチンの[Job](https://kotlinlang.org/api/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-job/index.html)は、コンテキストの一部であり、`coroutineContext[Job]`式を使うことで取り出すことができる。
```Kotlin
import kotlinx.coroutines.*

fun main() = runBlocking<Unit> {
    println("My job is ${coroutineContext[Job]}")    
}
```
[デバッグモード](https://kotlinlang.org/docs/coroutine-context-and-dispatchers.html#debugging-coroutines-and-threads)では、このような出力になる。
`My job is "coroutine#1":BlockingCoroutine{Active}@6d311334`
留意すべきは、[CoroutineScope](https://kotlinlang.org/api/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-scope/index.html)の[isActive](https://kotlinlang.org/api/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/is-active.html)は、単に`coroutineContext[Job]?.isActive == true`の便利なショートカットである。
## コルーチンの子孫
コルーチンが他のコルーチンの[CoroutineScope](https://kotlinlang.org/api/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-scope/index.html)から起動すると、それは[CoroutineScope.coroutineContext](https://kotlinlang.org/api/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-scope/coroutine-context.html)経由でコンテキストを継承し、新しいコルーチンの[Job](https://kotlinlang.org/api/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-job/index.html)は、親のコルーチンのjobの子になる。親のコルーチンがキャンセルされると、そのすべての子も再帰的にキャンセルされる。
しかし、この親子関係は、次の二つの方法のいずれかで明示的にオーバーライドできる。
1. コルーチンを起動するときに異なるスコープ(例として`GlobalScope.launch`)が明示的に指定された場合、それは親のスコープから`Job`を継承しない。
1. 異なる`Job`オブジェクトが新しいコルーチンのためのコンテキストとして渡されるとき(以下の例でお見せするように)、親のスコープの`Job`を上書きする。

両方のケースにおいても、起動したコルーチンは、起動元のスコープとは結びついておらず、独立して働く。
```Kotlin
import kotlinx.coroutines.*

fun main() = runBlocking<Unit> {
    // ある種の要求を処理するコルーチンを起動する
    val request = launch {
        // 他の二つのJobを生成する
        launch(Job()) { 
            println("job1: I run in my own Job and execute independently!")
            delay(1000)
            println("job1: I am not affected by cancellation of the request")
        }
        // そして別のものは親のコンテキストを継承する
        launch {
            delay(100)
            println("job2: I am a child of the request coroutine")
            delay(1000)
            println("job2: I will not execute this line if my parent request is cancelled")
        }
    }
    delay(500)
    request.cancel() // 要求の処理をキャンセルする
    println("main: Who has survived request cancellation?")
    delay(1000) // 何が起こるか見るために1秒間メインスレッドを遅延させる
}
```
このコードの出力は次のようになる。
```
job1: I run in my own Job and execute independently!
job2: I am a child of the request coroutine
main: Who has survived request cancellation?
job1: I am not affected by cancellation of the request
```
## 親の責任
親のコルーチンは常にすべての子の完了を待つ。親は起動したすべての子を明示的に追跡する必要はなく、最後にそれらを待つために[Job.join](https://kotlinlang.org/api/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-job/join.html)を使う必要はない。
```Kotlin
import kotlinx.coroutines.*

fun main() = runBlocking<Unit> {
    // ある種の要求を処理するコルーチンを起動する
    val request = launch {
        repeat(3) { i -> // いくつかの子のジョブを起動する
            launch  {
                delay((i + 1) * 200L) // 遅延の変数 200ms, 400ms, 600ms
                println("Coroutine $i is done")
            }
        }
        println("request: I'm done and I don't explicitly join my children that are still active")
    }
    request.join() // すべての子を含む要求の完了を待つ
    println("Now processing of the request is complete")
}
```
結果は次のようになる。
```
request: I'm done and I don't explicitly join my children that are still active
Coroutine 0 is done
Coroutine 1 is done
Coroutine 2 is done
Now processing of the request is complete
```
## デバッグのためのコルーチンのネーミング
自動的に割り当てられたIDはコルーチンが度々ログ出力をし、同じコルーチンから来るログ記録を関連付ける必要があるだけのときは良い。しかし、コルーチンがと特定の要求の処理や、いくつかの特定のバックグラウンドタスクの実行と結びついている場合、デバッグ目的のために、明示的に命名する方が良い。[CoroutineName](https://kotlinlang.org/api/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-name/index.html)コンテキスト要素は、スレッド名と同じ目的のために役に立つ。[デバッグモード](https://kotlinlang.org/docs/coroutine-context-and-dispatchers.html#debugging-coroutines-and-threads)がONのとき、それにはそのコルーチンを実行しているスレッド名が含まれる。
次の例は、この概念を示している。
```Kotlin
import kotlinx.coroutines.*

fun log(msg: String) = println("[${Thread.currentThread().name}] $msg")

fun main() = runBlocking(CoroutineName("main")) {
    log("Started main coroutine")
    // 二つのバックグラウンドでの値の計算を実行する。
    val v1 = async(CoroutineName("v1coroutine")) {
        delay(500)
        log("Computing v1")
        252
    }
    val v2 = async(CoroutineName("v2coroutine")) {
        delay(1000)
        log("Computing v2")
        6
    }
    log("The answer for v1 / v2 = ${v1.await() / v2.await()}")    
}
```
`-Dkotlinx.coroutines.debug`JVMオプションをつけて生成された出力は、次のものと同様である。
```
[main @main#1] Started main coroutine
[main @v1coroutine#2] Computing v1
[main @v2coroutine#3] Computing v2
[main @main#1] The answer for v1 / v2 = 42
```
## コンテキスト要素の結合
時々、コルーチンコンテキストに対して、複数の要素を定義する必要がある。そのために`+`演算子を使うことができる。例えば、明示的に特定のディスパッチャーと、明示的に特定の名前が同時についた、コルーチンを起動することができる。
```Kotlin
import kotlinx.coroutines.*

fun main() = runBlocking<Unit> {
    launch(Dispatchers.Default + CoroutineName("test")) {
        println("I'm working in thread ${Thread.currentThread().name}")
    }    
}
```
`-Dkotlinx.coroutines.debug`JVMオプションをつけた、このコードの出力は次のようになる。
```
I'm working in thread DefaultDispatcher-worker-1 @test#2
```
## コルーチンのスコープ
コンテキスト、子とジョブについて一緒に知識を活用しよう。ライフサイクルを持つオブジェクトがあるが、オブジェクトはコルーチンではないアプリケーションを仮定する。例えば、我々はAndroidアプリケーションを書いており、Android Activityのコンテキストの中で様々なコルーチンを起動し、データを取得、更新、アニメーション等々のために非同期の操作を実行する。これらすべてのコルーチンは、Activityがメモリリークを防ぐために破壊されるとき、キャンセルされなければならない。もちろん、コンテキストとジョブを操作して、Activityのライフサイクルとコルーチンを手動で結びつけることはできるが、`kotlinx.coroutines`にはそれを抽象的なカプセル化である[CoroutineScope](https://kotlinlang.org/api/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-scope/index.html)が提供されている。すべてのコルーチンビルダーは、それの拡張で制限されているため、すでにコルーチンスコープについては精通しているはずである。
Activityのライフサイクルに結びついた[CoroutineScope](https://kotlinlang.org/api/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-scope/index.html)のインスタンスを作ることにより、コルーチンのライフサイクルを管理する。`CoroutineScope`インスタンスは[CoroutineScope()](https://kotlinlang.org/api/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-scope.html)か、[MainScope()](https://kotlinlang.org/api/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-main-scope.html)ファクトリ関数により作ることができる。前者は一般的な目的のスコープを作り、一方、後者はUIアプリケーション用のスコープを作り、デフォルトのディスパッチャーとして[Dispatchers.Main](https://kotlinlang.org/api/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-dispatchers/-main.html)を使う。
```Kotlin
class Activity {
    private val mainScope = MainScope()

    fun destroy() {
        mainScope.cancel()
    }
    // 続く
```
これで定義された`scope`を使い、この`Activity`のスコープ内でコルーチンを起動することができる。デモののため、バラバラの時間遅延する10個のコルーチンを起動する。
```Kotlin
// Activityクラスの続き
    fun doSomething() {
        // デモのため10のコルーチンを起動し、それぞれ異なる時間動作する
        repeat(10) { i ->
            mainScope.launch {
                delay((i + 1) * 200L) // 遅延変数 200ms, 400ms, ... など
                println("Coroutine $i is done")
            }
        }
    }
} // Activityクラスの終了
```
Activityを作成するmain関数では、テストの`doSomething`関数を呼び、500ms後にActivityを破壊する。これは`doSomething`から起動されたすべてのコルーチンをキャンセルする。Activityの破壊の後では、たとえ少し長く待ったとしても、もうメッセージが出力されないことからわかる。
```Kotlin
fun main() = runBlocking<Unit> {
    val activity = Activity()
    activity.doSomething() // テスト関数を実行
    println("Launched coroutines")
    delay(500L) // 500msの間遅延
    println("Destroying activity!")
    activity.destroy() // すべてのコルーチンをキャンセルする
    delay(1000) // それらが動かないことを視覚的に確認する。    
}
```
この例の出力は以下のようになる。
```
Launched coroutines
Coroutine 0 is done
Coroutine 1 is done
Destroying activity!
```
ご覧のとおり、最初の二つのコルーチンがメッセージを出力するだけで、他は`Activity.destroy()`での単一の`job.cancel`の呼び出しによってキャンセルされる。

::: note
留意すべきは、Androidはライフサイクルを持つすべての実体で、コルーチンスコープの提供者サポートを持つ。[対応するドキュメント](https://developer.android.com/topic/libraries/architecture/coroutines#lifecyclescope)を参照のこと。
:::
## スレッドローカルデータ
時々、いくつかのスレッドローカルなデータをコルーチンに対して、あるいはコルーチン間で送る能力があると便利である。しかしそれらは特定のスレッドに縛られていないので、もし手動で行うとボイラープレートコードに至りそうである。
`[ThreadLocal](https://docs.oracle.com/javase/8/docs/api/java/lang/ThreadLocal.html)`のため、[asContextElement](https://kotlinlang.org/api/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/as-context-element.html)拡張関数が、助けのために存在する。それは追加のコンテキスト要素を作り、与えられた`ThreadLocal`の値を保持し、コルーチンがコンテキストを切り替えるときはいつでも復元する。
動かして実演するのは簡単である。
```Kotlin
import kotlinx.coroutines.*

val threadLocal = ThreadLocal<String?>() //thread-local変数の宣言

fun main() = runBlocking<Unit> {
    threadLocal.set("main")
    println("Pre-main, current thread: ${Thread.currentThread()}, thread local value: '${threadLocal.get()}'")
    val job = launch(Dispatchers.Default + threadLocal.asContextElement(value = "launch")) {
        println("Launch start, current thread: ${Thread.currentThread()}, thread local value: '${threadLocal.get()}'")
        yield()
        println("After yield, current thread: ${Thread.currentThread()}, thread local value: '${threadLocal.get()}'")
    }
    job.join()
    println("Post-main, current thread: ${Thread.currentThread()}, thread local value: '${threadLocal.get()}'")    
}
```
この例では、[Dispatchers.Default](https://kotlinlang.org/api/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-dispatchers/-default.html)を使ってバックグラウンドのスレッドプールで新しいコルーチンを起動する。そのため、それはスレッドプールから異なるスレッド上で動作するが、`threadLocal.asContextElement(value = "launch")`を使って指定されたスレッドローカル変数の値は、コルーチンがどんなスレッドで実行しても。持ったままである。したがって出力は([debug](https://kotlinlang.org/docs/coroutine-context-and-dispatchers.html#debugging-coroutines-and-threads)で)次のようになる。
```
Pre-main, current thread: Thread[main @coroutine#1,5,main], thread local value: 'main'
Launch start, current thread: Thread[DefaultDispatcher-worker-1 @coroutine#2,5,main], thread local value: 'launch'
After yield, current thread: Thread[DefaultDispatcher-worker-2 @coroutine#2,5,main], thread local value: 'launch'
Post-main, current thread: Thread[main @coroutine#1,5,main], thread local value: 'main'
```
対応するコンテキスト要素をセットすることは忘れやすい。コルーチンを実行しているスレッドが異なる場合、コルーチンからアクセスされるスレッドローカル変数は、そのとき予期せぬ値を持っているかもしれない。そのような状況を避けるため、[ensurePreset](https://kotlinlang.org/api/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/ensure-present.html)メソッドを使い、不適切な使用の場合は早期に失敗すさせることが推奨されている。
`ThreadLocal`は最上級のサポートを持ち、`kotlinx.coroutines`が提供するどんなプリミティブ値も使うことができる。ただし一つ制限がある。スレッドローカルが変更されると、新しい値はコルーチンの呼び出し元には伝播せず(なぜならコンテキスト要素はすべての`ThreadLocal`値へのアクセスを追跡できないため)、変更された値は次の一時停止で失われる。コルーチンでスレッドローカルの値を更新するには、[withContext](https://kotlinlang.org/api/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/with-context.html)を使い、詳細は[asContextElement](https://kotlinlang.org/api/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/as-context-element.html)を参照のこと。
あるいは、`class Counter(var i: Int)`のように値を変更可能な箱に格納し、それにスレッドローカルな値を格納することもできる。しかしこのケースでは、この変更可能な箱の値に対する潜在的な同時変更を同期することに完全に責任を持たなければならない。
さらに高度な使い方、例えばログのMDCの統合や、トランザクションコンテキストや、値を渡すためにスレッドローカルを内部的に使う他のライブラリの例のために、実装すべき[ThreadContextElement](https://kotlinlang.org/api/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-thread-context-element/index.html)インターフェイスの文書を参照のこと。