LoginSignup
157
126

More than 5 years have passed since last update.

【Kotlin】Coroutineを理解する

Last updated at Posted at 2018-09-30

はじめに

Kotlin 1.1からCoroutineが実験的に組み込まれました。
Coroutineとは「特定のスレッドに束縛されない、中断可能な計算インスタンス」です。
非同期処理で用いられますが、Threadよりも軽量で、実行途中で処理を中断・再開することができます。

準備

Coroutineを利用するために、build.gradleに下記の情報を追記します。
今回は2018/09/30時点での最新版(0.30.0)を使用しています。
更新状況はここから確認できます。

build.gradle
dependencies {
    ...
    implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:0.30.0"
}
build.gradle
kotlin {
    experimental {
        coroutines 'enable'
    }
}
build.gradle
repositories {
    jcenter()
}

使い方

Coroutineの作成にはCoroutineビルダーを使用します。

runBlocking

現在のスレッドをブロックするビルダーです。任意の型を返します。

runBlocking {
    // 何かしらの処理
}

Sample

fun main(args:Array<String>) {
    println(1)
    runBlocking {
        println(2)
    }
    println(3)
}

/**
 * 実行結果
 * 1
 * 2
 * 3
 */

launch

戻り値としてJobを返すビルダーです。

0.26.1からlaunchGlobalScope.launchになりました。

GlobalScope.launch {
    // 何かしらの処理 
}

Sample

現在のスレッドをブロックしないため、launch内の処理が実行される前にプログラムが終了します。

fun main(args:Array<String>) {
    println(1)
    launch {
        println(2)
    }
    println(3)
}

/**
 * 実行結果
 * 1
 * 3
 */

引数で実行するスレッドを指定できます。
引数なしの場合はDispatchers.Defaultが設定されます。

0.26.1からCommonPoolDispatchers.Defaultになりました。
0.26.1からUIDispatchers.Unconfinedになりました。

/**
 * Dispatchers.Default -> バックグラウンドスレッド
 * Dispatchers.Unconfined -> メインスレッド
 */
GlobalScope.launch(Dispatchers.Unconfined) {
    // 何かしらの処理 
}

Job#join()を利用すれば、呼び出し先のcoroutineの終了まで呼び出し元のcoroutineを中断できます。

runBlocking {
    GlobalScope.launch() {
        // 何かしらの処理 
    }.join()
}

Sample

fun main(args:Array<String>) = runBlocking {
    println(1)
    GlobalScope.launch {
        println(2)
    }.join()
    println(3)
}

/**
 * 実行結果
 * 1
 * 2
 * 3
 */

async

戻り値としてDeferred<T>を返すビルダーです。
Coroutineの処理が終わったタイミングで戻り値を取得できます。

0.26.1からasyncGlobalScope.asyncになりました。

GlobalScope.async {
    // 何かしらの処理 
}

Sample

launch同様、現在のスレッドをブロックしないため、async内の処理が実行されません。

fun main(args:Array<String>) {
    println(1)
    GlobalScope.async {
        println(2)
    }
    println(3)
}

/**
 * 実行結果
 * 1
 * 3
 */

Job#join()同様、Deferred<T>#await()を利用すれば、呼び出し先のCoroutineの終了まで呼び出し元のCoroutineを中断できます。

runBlocking {
    GlobalScope.async {
        // 何かしらの処理 
    }.await()
}

Sample

fun main(args:Array<String>) = runBlocking {
    println(1)
    GlobalScope.async {
        println(2)
    }.await()
    println(3)
}

/**
 * 実行結果
 * 1
 * 2
 * 3
 */

Suspend関数

Coroutineを中断できる関数です。suspendをつけることで宣言できます。
CoroutineかSuspend関数内からのみ実行できます。

suspend fun sampleSuspending(){
     // 何かしらの処理       
}

Sample

delayはSuspend関数なので実行できます。

fun main(args:Array<String>) = runBlocking {
    println(1)
    sampleSuspending()
    println(3)
}

suspend fun sampleSuspending() {
    delay(1000)
    println(2) 
}

/**
 * 実行結果
 * 1
 * (1秒中断)
 * 2
 * 3
 */ 

まとめ

非同期処理を直感的に理解しやすく、とても簡潔に記述できるようになりました。

参考

Coroutines - Kotlin Programming Language
AndroidでKotlin Coroutinesを使ってみる
eaglesakuraの技術ブログ
Kotlin の Coroutine を概観する
入門Kotlin coroutines

157
126
3

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
157
126