web-dev-qa-db-ja.com

Kotlinコルーチンは「前に起こる」保証をしますか?

Kotlinコルーチンは「前に起こる」保証を提供しますか?

たとえば、この場合、mutableVarへの書き込みと、(可能性としては)他のスレッドでのその後の読み取りとの間に「前に発生する」保証があります。

suspend fun doSomething() {
    var mutableVar = 0
    withContext(Dispatchers.IO) {
        mutableVar = 1
    }
    System.out.println("value: $mutableVar")
}

編集:

たぶん、追加の例は、(変更可能性を除いて)Kotlinっぽいので、問題をより明確にするでしょう。このコードはスレッドセーフですか?

suspend fun doSomething() {
    var data = withContext(Dispatchers.IO) {
        Data(1)
    }
    System.out.println("value: ${data.data}")
}

private data class Data(var data: Int)
10
Vasiliy

記述したコードには、共有状態への3つのアクセスがあります。

var mutableVar = 0                        // access 1, init
withContext(Dispatchers.IO) {
    mutableVar = 1                        // access 2, write
}
System.out.println("value: $mutableVar")  // access 3, read

3つのアクセスは厳密に順番に並べられ、それらの間には同時性がありません。KotlinのインフラストラクチャがIOスレッドに渡すときにhappens-before Edgeを確立することで安心できます。プールして、呼び出し元のコルーチンに戻ります。

次に、より説得力のある同等の例を示します。

launch(Dispatchers.Default) {
    var mutableVar = 0             // 1
    delay(1)
    mutableVar = 1                 // 2
    delay(1)
    println("value: $mutableVar")  // 3
}

delayは一時停止可能な関数であり、スレッドプールによってサポートされるDefaultディスパッチャーを使用しているため、1、2、3行目はそれぞれ異なるスレッドで実行される可能性があります。したがって、happen-beforeの保証に関する質問は、この例にも同様に当てはまります。一方、この場合、このコードの動作が順次実行の原則と一致していることは完全に明白です(私はそう思います)。

6
Marko Topolnik

Kotlinのコルーチンは、保証の前に発生します。

ルールは次のとおりです。コルーチン内では、コードpriorからサスペンド関数呼び出しへhappens beforeコードafterサスペンド呼び出し。

コルーチンは通常のスレッドのように考える必要があります。

Kotlinのコルーチンは複数のスレッドで実行できますが、変更可能な状態の観点からはスレッドと同じです。同じコルーチンの2つのアクションを同時に実行することはできません。

ソース: https://proandroiddev.com/what-is-concurrent-access-to-mutable-state-f386e5cb8292

コード例に戻ります。特にラムダがコルーチンである場合、ラムダ関数本体で変数をキャプチャすることは最良のアイデアではありません。ラムダの前のコードは、内部のコードの前には発生しません。

参照 https://youtrack.jetbrains.com/issue/KT-15514

3