Coroutines(コルーチン)は、kotlinx.coroutinesライブラリを通じて利用可能な、Kotlinにおける非同期プログラミングのための軽量スレッドです。JetBrains Kotlin Documentation, 2026によると、Coroutinesは従来のThreadとは異なり、スレッドをブロックせずに関数実行を一時停止できます。コルーチンは制限されたスレッドプール上で実行されるため、ネイティブスレッドよりも千倍軽量です。Kotlin CoroutinesはAndroid Jetpack、Retrofit、Room、およびその他のAndroidエコシステムの人気ライブラリと完全に統合されています。
重要ポイント
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は、関数を一時停止可能としてマークするKotlinキーワードです。このような関数は、別のsuspend関数またはコルーチンからのみ呼び出すことができます。suspend関数内では、任意の順序で他のsuspend関数を呼び出すことができ、各呼び出しポイントは潜在的な一時停止ポイントです。
メカニズムはシンプルです:suspend関数が別のsuspend関数を呼び出すと、そのポイントで一時停止し、スレッドを解放します。呼び出された関数が完了すると、ランタイムは保存された場所から実行を続行します。これは協調的キャンセル(cooperative cancellation)と呼ばれます — スレッドはブロックされません。
重要:suspend関数はデフォルトでは非同期ではありません。launchやasyncを使用しない場合、実行順序はシーケンシャルです。suspendは単に関数がスレッドをブロックせずに一時停止し、コルーチンコンテキストの一部になることを可能にします。Continuation Passing Styleは、各suspend関数が隠れたContinuationコールバックを受け取り、コンパイラが一時停止と再開を管理するステートマシンを生成するコンパイルモデルです。
CoroutineScopeは、コルーチンのライフサイクルを定義するコンテキストです。すべてのコルーチンはスコープ内で起動される必要があります。スコープがキャンセルされると(例:Activityの終了時)、そのすべての子コルーチンが自動的にキャンセルされます。これにより、バックグラウンドタスクのリークを防ぎます。Android Jetpackは各コンポーネントに既製のスコープを提供します:ViewModel用のviewModelScope、Activity/Fragment用のlifecycleScope。これらは対応するコンポーネントが破棄されると自動的にキャンセルされます。
構造化された並行処理(Structured Concurrency)は、すべての子コルーチンが完了するまでコルーチンが完了しないことを保証する原則です。Job階層はツリーを形成します:ルートコルーチンが親ジョブを作成し、子が子ジョブを作成します。親ジョブのキャンセルはすべての子に伝播します。Structured Concurrencyはコルーチンとスレッドの基本的な違いです。
| Scope | 使用場所 | キャンセル |
|---|---|---|
| GlobalScope | デーモンタスクのみ | 自動キャンセルされない |
| viewModelScope | Android ViewModel | ViewModelクリア時 |
| lifecycleScope | Android Activity/Fragment | ライフサイクル破棄時 |
| coroutineScope | suspend関数内 | 親ジョブキャンセル時 |
通常のJobは、1つの子コルーチンが失敗するとすべての兄弟をキャンセルします。SupervisorJobは例外です:1つの子コルーチンの失敗は他に影響しません。これは、複数の独立したタスクが並行して実行され、そのうちの1つが他のタスクをキャンセルせずにクラッシュする可能性がある場合に重要です。
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開発で最もよく使われるビルダーです。
launch — コルーチンを起動し、Jobを返し、結果を返しません(fire-and-forget)。async — コルーチンを起動し、awaitを介して結果を取得できるDeferredを返します。runBlocking — コルーチンを実行するために現在のスレッドをブロックします(テストとmain関数のみ)。ビルダーの選択はシナリオに依存します:launchはイベントや更新に適しており、asyncは結果を伴うタスクに、runBlockingはテストやエントリポイントのみに使用します。
3つの実践的なシナリオを見てみましょう:launchを使用した基本コルーチン、asyncを使用した並列呼び出し、SupervisorJobを使用したエラー処理。
viewModelScope.launchはViewModelコンテキストでコルーチンを起動します。ViewModelがクリアされると、コルーチンは自動的にキャンセルされます。
class ProfileViewModel : ViewModel() {
fun loadUser() {
viewModelScope.launch(Dispatchers.IO) {
val user = api.fetchUser()
withContext(Dispatchers.Main) {
showUser(user)
}
}
}
}
coroutineScopeとasyncは3つのリクエストを並列に起動します。結果は.await()を介して収集されます。いずれかのリクエストが失敗すると、すべてがキャンセルされます。
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は各コルーチンが独立して完了することを許可します。1つのリクエストのエラーは他をキャンセルしません。
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) }
}
スレッド(Thread)はオペレーティングシステムのプリミティブです。各スレッドには独自のスタック(約1 MB)があり、作成と切り替えにシステムコールが必要です。コルーチンは言語プリミティブであり、OSに縛られません。状態を保存するためにContinuationを使用し、システムコールなしでランタイムレベルで切り替えます。
Google(2025)によると、スレッドの代わりにコルーチンを使用すると、Androidアプリケーションのバックグラウンドタスクのメモリ消費が90〜95%削減されます。すべての最新Androidライブラリ(Retrofit、Room、WorkManager)は、suspend関数を介したコルーチンサポートを内蔵しています。Ktor(JetBrainsのHTTPクライアントフレームワーク)も完全にコルーチン上に構築されており、コールバックAPIなしで各リクエストにsuspend関数を提供します。RoomはDAOのsuspend関数を介してコルーチンをサポートし、メインスレッドをブロックせずにデータベースクエリを実行できます。
スレッドは、JNIを介したネイティブコード、長時間のCPU負荷の高いブロッキング呼び出し(ビデオレンダリング、シミュレーション)、Cライブラリとの統合に必要です。それ以外のすべてにはコルーチンを使用します。
よくある質問
コルーチンは、既存のスレッド上で実行される一時停止可能な作業単位です。スレッドは独自のスタックを持つシステムリソースです。コルーチンはスレッドよりも数千倍軽量で、一時停止時にリソースをブロックしません。
Dispatchers.IOはブロッキングI/O操作(ネットワーク、ファイル)用に設計されており、必要に応じて新しいスレッドを作成できます。Dispatchers.DefaultはCPU負荷の高い計算用に固定サイズのプール(CPUコア数)を持ちます。
Job.cancel()でコルーチンとそのすべての子をキャンセルします。コルーチン内でキャンセルを確認するには、ensureActive()を使用します — コルーチンがキャンセルされている場合、CancellationExceptionをスローします。
はい — kotlinx-coroutines-rx3ライブラリを介して使用できます。Observable/Singleをsuspend関数に変換したり、flowableを介して戻したりするためのawaitSingle、awaitFirstなどの関数を提供します。
Flowはコールド非同期データストリームであり、コルーチンにおけるRxJava Observableの相当品です。Flowは値を順次発行し、例外または成功で完了します。map、filter、catchなどのオペレーターをサポートします。
まとめ
ターンキー方式のモバイルアプリケーションを開発します
IT Sectrは2017年からスタートアップや企業向けにiOS・Androidアプリケーションを開発しています。私たちがご相談に乗り、最適なソリューションをご提案します。