Coroutines — 主要概念、KotlinのJobとDispatchers

著者: IT Sectr 公開日: 2026-03-16 読了時間: 8 分

Coroutines(コルーチン)は、kotlinx.coroutinesライブラリを通じて利用可能な、Kotlinにおける非同期プログラミングのための軽量スレッドです。JetBrains Kotlin Documentation, 2026によると、Coroutinesは従来のThreadとは異なり、スレッドをブロックせずに関数実行を一時停止できます。コルーチンは制限されたスレッドプール上で実行されるため、ネイティブスレッドよりも千倍軽量です。Kotlin CoroutinesはAndroid Jetpack、Retrofit、Room、およびその他のAndroidエコシステムの人気ライブラリと完全に統合されています。

重要ポイント

  • Coroutines — ブロッキングなしの非同期コードのための軽量Kotlinスレッド
  • suspend関数 — スレッドをブロックせずに一時停止および再開できる関数
  • Dispatcherはコルーチン実行のスレッドプールを決定します
  • Job — キャンセルサポートと状態追跡を備えたコルーチンデスクリプタ
  • CoroutineScopeはコルーチンのライフサイクルと完了時のキャンセルを管理します

Kotlinコルーチンとは

Coroutinesは、kotlinx.coroutinesライブラリに実装されたKotlinの非同期プログラミングメカニズムです。オペレーティングシステムのスレッドとは異なり、コルーチンは特定のスレッドに縛られません。あるスレッドで一時停止し、別のスレッドで再開できます。単一のスレッドで最小限のオーバーヘッドで何千ものコルーチンを実行できます。

コルーチンはKotlin 1.3(2018)で実験的機能として登場し、Kotlin 1.5(2021)で安定版になりました。Coroutinesはasync/awaitと同様にコールバック地獄の問題を解決しますが、より豊富なAPIを提供します:チャネル(Channel)、Flow、Job階層での例外処理、Android Lifecycleとの直接統合。

JetBrains(2025)によると、各コルーチンは約100バイトのメモリを消費し、ネイティブスレッドは1+ MBです。これにより、OutOfMemoryErrorのリスクなしに単一のアプリケーションで数百万のコルーチンを実行できます。コルーチンの軽量性こそが、Androidでの非同期処理に好まれるツールとなっている理由です。

コルーチンの内部動作

各KotlinコルーチンはContinuation Passing Style(CPS)を介してステートマシンにコンパイルされます。コンパイラは各suspend関数に隠れたContinuationパラメータを追加します。Continuationには再開ポイントとすべてのローカル変数が含まれます。コルーチンが一時停止すると、ランタイムはContinuationを保存し、再開時にDispatcherプールの利用可能な任意のスレッドで復元します。

suspend関数: 一時停止と再開

suspendは、関数を一時停止可能としてマークするKotlinキーワードです。このような関数は、別のsuspend関数またはコルーチンからのみ呼び出すことができます。suspend関数内では、任意の順序で他のsuspend関数を呼び出すことができ、各呼び出しポイントは潜在的な一時停止ポイントです。

メカニズムはシンプルです:suspend関数が別のsuspend関数を呼び出すと、そのポイントで一時停止し、スレッドを解放します。呼び出された関数が完了すると、ランタイムは保存された場所から実行を続行します。これは協調的キャンセル(cooperative cancellation)と呼ばれます — スレッドはブロックされません。

  • 一時停止 — コルーチンはスレッドをブロックせずに解放します
  • 再開 — コルーチンは一時停止した場所から続行します
  • スレッド — コルーチンはスレッドAで一時停止し、スレッドBで再開できます
  • 例外 — 同期コードと同様にtry/catchで処理されます

重要:suspend関数はデフォルトでは非同期ではありません。launchやasyncを使用しない場合、実行順序はシーケンシャルです。suspendは単に関数がスレッドをブロックせずに一時停止し、コルーチンコンテキストの一部になることを可能にします。Continuation Passing Styleは、各suspend関数が隠れたContinuationコールバックを受け取り、コンパイラが一時停止と再開を管理するステートマシンを生成するコンパイルモデルです。

CoroutineScopeと構造化された並行処理

CoroutineScopeは、コルーチンのライフサイクルを定義するコンテキストです。すべてのコルーチンはスコープ内で起動される必要があります。スコープがキャンセルされると(例:Activityの終了時)、そのすべての子コルーチンが自動的にキャンセルされます。これにより、バックグラウンドタスクのリークを防ぎます。Android Jetpackは各コンポーネントに既製のスコープを提供します:ViewModel用のviewModelScope、Activity/Fragment用のlifecycleScope。これらは対応するコンポーネントが破棄されると自動的にキャンセルされます。

構造化された並行処理(Structured Concurrency)は、すべての子コルーチンが完了するまでコルーチンが完了しないことを保証する原則です。Job階層はツリーを形成します:ルートコルーチンが親ジョブを作成し、子が子ジョブを作成します。親ジョブのキャンセルはすべての子に伝播します。Structured Concurrencyはコルーチンとスレッドの基本的な違いです。

Scope使用場所キャンセル
GlobalScopeデーモンタスクのみ自動キャンセルされない
viewModelScopeAndroid ViewModelViewModelクリア時
lifecycleScopeAndroid Activity/Fragmentライフサイクル破棄時
coroutineScopesuspend関数内親ジョブキャンセル時

エラー処理のためのSupervisorJob

通常のJobは、1つの子コルーチンが失敗するとすべての兄弟をキャンセルします。SupervisorJobは例外です:1つの子コルーチンの失敗は他に影響しません。これは、複数の独立したタスクが並行して実行され、そのうちの1つが他のタスクをキャンセルせずにクラッシュする可能性がある場合に重要です。

Dispatchersとコルーチンビルダー

Dispatchersは、コルーチンが実行されるスレッドを決定します。Dispatchers.Main — メインのAndroid UIスレッド。Dispatchers.IO — ブロッキング操作(ネットワーク、ディスク)用のプール。Dispatchers.Default — CPU負荷の高いタスク用。Dispatchers.Unconfined — 現在のスレッドで開始しますが、そのスレッドに留まることは保証しません。適切なDispatcherを選択することはパフォーマンスにとって重要です:DefaultでIOタスクを実行すると計算プールがブロックされ、IOでCPUタスクを実行すると不要なスレッドが作成されます。

withContext — コルーチン内でDispatcherを切り替える関数です。例えば、JSONを解析するsuspend関数は、計算のためにDispatchers.Defaultに切り替え、UI更新のためにDispatchers.Mainに戻ることができます。withContextはAndroid開発で最もよく使われるビルダーです。

3つの主要なコルーチンビルダー

launch — コルーチンを起動し、Jobを返し、結果を返しません(fire-and-forget)。async — コルーチンを起動し、awaitを介して結果を取得できるDeferredを返します。runBlocking — コルーチンを実行するために現在のスレッドをブロックします(テストとmain関数のみ)。ビルダーの選択はシナリオに依存します:launchはイベントや更新に適しており、asyncは結果を伴うタスクに、runBlockingはテストやエントリポイントのみに使用します。

Kotlinでのコルーチンを使ったコード例

3つの実践的なシナリオを見てみましょう:launchを使用した基本コルーチン、asyncを使用した並列呼び出し、SupervisorJobを使用したエラー処理。

launchでコルーチンを起動

viewModelScope.launchはViewModelコンテキストでコルーチンを起動します。ViewModelがクリアされると、コルーチンは自動的にキャンセルされます。

kotlin
class ProfileViewModel : ViewModel() {
    fun loadUser() {
        viewModelScope.launch(Dispatchers.IO) {
            val user = api.fetchUser()
            withContext(Dispatchers.Main) {
                showUser(user)
            }
        }
    }
}

asyncによる並列リクエスト

coroutineScopeとasyncは3つのリクエストを並列に起動します。結果は.await()を介して収集されます。いずれかのリクエストが失敗すると、すべてがキャンセルされます。

kotlin
suspend fun loadDashboard(): Dashboard = coroutineScope {
    val user = async { api.fetchUser() }
    val posts = async { api.fetchPosts() }
    val stats = async { api.fetchStats() }
    Dashboard(user.await(), posts.await(), stats.await())
}

SupervisorJobによるエラー処理

SupervisorJobは各コルーチンが独立して完了することを許可します。1つのリクエストのエラーは他をキャンセルしません。

kotlin
val scope = CoroutineScope(SupervisorJob() + Dispatchers.IO)
scope.launch {
    try { api.fetchUsers() } catch (e: Exception) { log(e) }
}
scope.launch {
    try { api.fetchPosts() } catch (e: Exception) { log(e) }
}

コルーチン vs スレッド: 比較とシナリオ

スレッド(Thread)はオペレーティングシステムのプリミティブです。各スレッドには独自のスタック(約1 MB)があり、作成と切り替えにシステムコールが必要です。コルーチンは言語プリミティブであり、OSに縛られません。状態を保存するためにContinuationを使用し、システムコールなしでランタイムレベルで切り替えます。

  • メモリ — スレッド約1 MB、コルーチン約100バイト。10,000倍の差
  • 作成 — スレッド約1 µsのsyscall、コルーチン約0.01 µs(JVMレベル)
  • 切り替え — スレッド約0.1 µs(syscall)、コルーチン約0.001 µs(continuation)
  • 最大数 — 数千のスレッド vs 数百万のコルーチン(デバイスあたり)
  • キャンセル — スレッドは外部からキャンセル不可(非推奨のThread.stop)、コルーチンはJob.cancel()で可能

Google(2025)によると、スレッドの代わりにコルーチンを使用すると、Androidアプリケーションのバックグラウンドタスクのメモリ消費が90〜95%削減されます。すべての最新Androidライブラリ(Retrofit、Room、WorkManager)は、suspend関数を介したコルーチンサポートを内蔵しています。Ktor(JetBrainsのHTTPクライアントフレームワーク)も完全にコルーチン上に構築されており、コールバックAPIなしで各リクエストにsuspend関数を提供します。RoomはDAOのsuspend関数を介してコルーチンをサポートし、メインスレッドをブロックせずにデータベースクエリを実行できます。

スレッドをコルーチンの代わりに使用すべき場合

スレッドは、JNIを介したネイティブコード、長時間のCPU負荷の高いブロッキング呼び出し(ビデオレンダリング、シミュレーション)、Cライブラリとの統合に必要です。それ以外のすべてにはコルーチンを使用します。

よくある質問

コルーチンとスレッドの違いは何ですか?

コルーチンは、既存のスレッド上で実行される一時停止可能な作業単位です。スレッドは独自のスタックを持つシステムリソースです。コルーチンはスレッドよりも数千倍軽量で、一時停止時にリソースをブロックしません。

Dispatchers.IOとは何ですか?Defaultとどう違いますか?

Dispatchers.IOはブロッキングI/O操作(ネットワーク、ファイル)用に設計されており、必要に応じて新しいスレッドを作成できます。Dispatchers.DefaultはCPU負荷の高い計算用に固定サイズのプール(CPUコア数)を持ちます。

実行中のコルーチンをキャンセルするには?

Job.cancel()でコルーチンとそのすべての子をキャンセルします。コルーチン内でキャンセルを確認するには、ensureActive()を使用します — コルーチンがキャンセルされている場合、CancellationExceptionをスローします。

コルーチンはRxJavaと一緒に使えますか?

はい — kotlinx-coroutines-rx3ライブラリを介して使用できます。Observable/Singleをsuspend関数に変換したり、flowableを介して戻したりするためのawaitSingle、awaitFirstなどの関数を提供します。

コルーチンにおけるFlowとは?

Flowはコールド非同期データストリームであり、コルーチンにおけるRxJava Observableの相当品です。Flowは値を順次発行し、例外または成功で完了します。map、filter、catchなどのオペレーターをサポートします。

まとめ

  • Coroutines — Continuation Passing Styleによるブロッキングなしの一時停止を備えた軽量Kotlinスレッド
  • suspend — 一時停止可能な関数をマークするキーワード
  • Dispatchersがスレッドプールを管理:Main、IO、Default
  • CoroutineScopeがコルーチンのライフサイクルをコンポーネント(Activity、ViewModel)にバインド
  • launchは結果なしでコルーチンを開始、async/awaitは結果あり
  • Structured Concurrencyが子コルーチンの階層的キャンセルを保証
  • コルーチン vs スレッド — コルーチンは10,000倍軽量でAndroidの標準

ターンキー方式のモバイルアプリケーションを開発します

IT Sectrは2017年からスタートアップや企業向けにiOS・Androidアプリケーションを開発しています。私たちがご相談に乗り、最適なソリューションをご提案します。

プロジェクトについて相談

こちらもお読みください