DispatchQueue: その概要、GCDキュー、マルチスレッドの基礎

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

DispatchQueueは、iOSおよびmacOSで非同期タスクを管理するためのGrand Central Dispatch(GCD)の基本的なキューです。Apple Developer Documentation, 2026によると、DispatchQueueはシリアルキューとコンカレントキューを通じて、開発者からスレッド管理を抽象化します。GCDはシステムスレッドプールにタスクを自動的に分散し、手動でのスレッド作成と破棄を不要にします。

重要なポイント

  • DispatchQueueはiOSで非同期コードを実行するためのGCDの主要な抽象化です
  • シリアルキューはタスクを厳密に順次実行し、競合状態を排除します
  • コンカレントキューはシステムスレッドプールを介して複数のタスクを並列実行します
  • QoSはタスクの優先順位を設定します — userInteractiveからbackgroundまで
  • DispatchQueue.mainはメインスレッドでUIKitを更新するための唯一のキューです

DispatchQueueとGrand Central Dispatchとは

DispatchQueueは、システムまたはカスタムスレッドキューでのタスク実行を管理するGrand Central Dispatch(GCD)フレームワークのオブジェクトです。Grand Central Dispatchは、iOS 4およびmacOS 10.6から利用可能なAppleの低レベルライブラリで、開発者からスレッド管理を完全に抽象化します。GCDはオペレーティングシステムのスレッドプールを使用し、デバイスの負荷に応じてスレッド数を自動的にスケーリングします。

開発者は手動でスレッドを作成および破棄する必要はありません — GCDがこのタスクを処理し、DispatchQueueを通じてシンプルなAPIを提供します。クロージャの形式のタスクは、syncまたはasyncメソッドを介してキューに送信されます。最初のケースでは、呼び出し元スレッドはタスクが完了するまでブロックされます。2番目のケースでは、実行は即座に継続されます。

Apple(2026年)によると、GCDはコア数と現在のCPU負荷に適応するシステムスレッドプールを使用します。コンカレントキューはタスクごとに新しいスレッドを作成するわけではありません — GCDはプールからスレッドを再利用し、スレッド作成のオーバーヘッドを最小限に抑えます。

GCDのアーキテクチャ

Grand Central Dispatchは、キュー(DispatchQueue)、グループ(DispatchGroup)、セマフォ(DispatchSemaphore)の3つの主要コンポーネントで構成されています。キューはコードブロックの形式でタスクを受け入れる主要な要素です。DispatchGroupは複数のタスクの実行を同期し、DispatchSemaphoreは共有リソースへのアクセスを特定のスレッド数に制限します。

各GCDキューは特定のQoS(Quality of Service)クラスに関連付けられており、システムにタスクの重要性を通知します。システムはキュー間でCPU時間を分配するためにQoSを使用し、UI更新やユーザータッチ処理など、より重要なタスクに優先順位を付けます。

シリアルキューとコンカレントキュー: 比較

シリアルキューはタスクを厳密に順次実行します。シリアルキューに3つのタスクを配置した場合、2番目のタスクは最初のタスクが完全に完了した後にのみ開始されます。シリアルキューは、共有リソースへのアクセスを同期するために使用されます — たとえば、コードの複数の部分から変更される配列などです。

コンカレントキューは複数のタスクを同時に実行し、システムプールから利用可能なスレッドに分散します。コンカレントキュー上のタスクはFIFO順で開始されますが、実行時間が異なる場合は任意の順序で完了します。コンカレントキューは完了順序を保証しません — 開始順序のみを保証します。

パラメータシリアルキューコンカレントキュー
実行順序厳密に順次並列
スレッド数1GCDプールから複数
用途共有リソースの保護独立した計算
メインキューあり(メインスレッド)なし
デッドロックリスク同じキューでsync時に高い低い

シリアルキューを選ぶべき場合

シリアルキューは、ファイルへの書き込み、データモデルの更新、Core Dataの操作など、共有状態を変更するタスクに最適です。シリアルキューを使用することで、コードの2つの部分が同時に同じデータを変更することを防ぎ、追加のロックなしで競合状態を排除できます。

コンカレントキューを選ぶべき場合

コンカレントキューは、互いに依存しないタスクに適しています:複数の画像の読み込み、並列ネットワークリクエスト、データのバッチ処理など。GCDはCPUコア数と現在のシステム負荷に基づいて、同時に実行するタスク数を自動的に決定します。

Quality of Service: タスク実行の優先順位

QoS(Quality of Service)は、タスクの重要性と緊急性をオペレーティングシステムに通知するGCDの仕組みです。システムはスレッドスケジューリングにQoSを使用します:高いQoSのタスクはより多くのCPU時間を取得し、早く開始されます。QoS値はキュー作成時または特定のタスク送信時に渡されます。

GCDでは5つのQoSクラスが利用可能です。.userInteractive — UI関連タスクの最高優先度。.userInitiated — ユーザーが開始したタスク用。.utility — 進捗を表示するバックグラウンドタスク用。.background — ユーザーから見えないタスク用。.default — userInitiatedとutilityの中間レベルで、デフォルトで使用されます。

Apple(2026年)によると、誤ったQoS選択はパフォーマンス問題の一般的な原因の1つです。QoS .userInteractiveでバックグラウンドダウンロードを実行するとUIのリソースを消費し、アニメーションにマイクロラグを引き起こします。許容可能な実行時間を提供する最低のQoSを選択することをお勧めします。

QoSの使用例

即座に表示する画像を読み込む場合は、.userInitiatedを使用します — ユーザーは結果を期待しています。次の画面をプリロードする場合は、.utilityで十分です。バックグラウンドでのサーバー同期は.backgroundで実行され、アクティブなタスクへの影響を最小限に抑えます。

DispatchGroupとセマフォ: タスク同期

DispatchGroupを使用すると、タスクグループの完了を追跡できます。グループ内のすべてのタスクが完了すると、GCDは指定されたキューでnotifyハンドラを呼び出します。これは、複数の独立したリソース(プロフィールデータ、友達リスト、設定など)を読み込む場合に特に便利で、すべてのデータを受信した後にのみインターフェースを更新する必要があります。

DispatchGroupは同期wait()呼び出しをサポートしており、すべてのタスクが完了するまで現在のスレッドをブロックします。これは、グループの結果なしではコードを続行できない場合に便利です。非同期バリアントのnotify()は、すべてのタスクが完了した後に指定されたキューでクロージャを呼び出し、呼び出し元スレッドをブロックしません。

並列性を制限するDispatchSemaphore

DispatchSemaphoreはリソースへのアクセスを制御し、同時アクセス数を制限します。初期値3のセマフォは最大3つの並列タスクを許可します。wait()を呼び出すとカウンタが減少し、signal()で増加します。カウンタがゼロになると、リソースが利用可能になるまでスレッドはブロックされます。

SwiftでのDispatchQueueコード例

SwiftでのDispatchQueueの使用例を3つ見てみましょう。1つ目はメインスレッドに戻る基本的なasync呼び出し、2つ目はシリアルキューによる同期、3つ目は並列リクエストのためのDispatchGroupです。

メインに戻る基本的なasync呼び出し

DispatchQueue.mainはメインスレッドのシリアルキューであり、UI操作専用です。バックグラウンド作業が完了した後、インターフェースを更新するために常にこれを使用してください。

swift
let queue = DispatchQueue.global(qos: .userInitiated)
queue.async {
    let data = self.fetchData()
    DispatchQueue.main.async {
        self.updateUI(with: data)
    }
}

共有リソース保護のためのシリアルキュー

一意の識別子を持つカスタムシリアルキューを作成すると、可変配列へのアクセスが同期されます。すべての読み取りおよび書き込み操作は単一のキューを通過し、競合状態を排除します。

swift
let serialQueue = DispatchQueue(label: "com.app.items")
var items: [Int] = []

serialQueue.async {
    items.append(1)
}
serialQueue.async {
    let last = items.last
    DispatchQueue.main.async {
        print("Last item: \(last)")
    }
}

並列リクエストのためのDispatchGroup

DispatchGroupを使用すると、コンカレントキューで複数のタスクを起動し、すべてが完了したときに通知を受け取ることができます。これはプロフィール画面のデータを読み込む際に便利です。

swift
let group = DispatchGroup()
let worker = DispatchQueue.global()

worker.async(group: group) { self.loadProfile() }
worker.async(group: group) { self.loadFriends() }
worker.async(group: group) { self.loadSettings() }

group.notify(queue: DispatchQueue.main) {
    self.showCompleteUI()
}

DispatchQueue使用時の一般的なエラー

シリアルキューでsyncを呼び出したときのデッドロックは最も一般的なエラーです。シリアルキュー上のタスクが同じキューでqueue.syncを呼び出すと、スレッドは永久にブロックされます。キューは現在のタスクの完了を待ち、タスクはsync呼び出しの完了を待つ — 古典的な相互ブロックです。

バックグラウンドスレッドからのUI更新

UIKitのすべての操作はメインスレッドで実行する必要があります。XcodeはMain Thread Checkerを通じてデバッグモードでこれらのエラーを検出します。リリースビルドでは、予期しない動作、アニメーションの未起動、UIの未更新、クラッシュが発生する可能性があります。

カスタムキューの過剰な作成

グローバルキューではなく何百ものカスタムキューを作成することはアンチパターンです。各キューはシステムリソースを消費します。ほとんどのタスクでは、異なるQoSレベルのグローバルコンカレントキューと、共有データを同期するための1〜2つのシリアルキューで十分です。

ループ内でのautoreleasepoolの無視

autoreleasepoolなしでバックグラウンドキューでリソース集約型のループタスクを実行すると、ループ全体が終了するまでメモリが増加し続けます。ARCはautoreleaseプールを出るときにのみオブジェクトを解放します。タイムリーなメモリ解放のために、ループ反復をautoreleasepool { }でラップしてください。

よくある質問

DispatchQueueとOperationQueueの違いは何ですか?

OperationQueueはGCDの上に構築されていますが、操作の依存関係、KVO、キャンセルサポートを備えたより高レベルのAPIを提供します。DispatchQueueは依存関係管理なしのシンプルな非同期タスクのための低レベルキューです。

DispatchQueue内のタスクを強制的に停止できますか?

GCDは実行中のタスクの停止をサポートしていません。suspend()メソッドは新しいタスクのみを一時停止し、現在のタスクは最後まで実行されます。キャンセルにはタスクコード内での手動フラグチェックが必要です。

ネットワークリクエストにはどのQoSを選択すべきですか?

即時結果表示が必要な主要リクエストには — .userInitiated。データのプリロードには — .utility。バックグラウンド同期には — .background

コンカレントキューはいくつのスレッドを使用しますか?

GCDはスレッド数を固定しません。スレッドプールは負荷に応じて動的にスケーリングされ、CPUコア、現在の負荷、各タスクのQoSを考慮します。最大数はシステムによって制限されます。

なぜDispatchQueue.mainがUIKitに必須なのですか?

UIKitはスレッドセーフではありません — そのすべてのクラスはメインスレッドからのみ呼び出す必要があります。違反すると、予期しない動作、更新の欠落、本番環境でのクラッシュが発生します。

まとめ

  • DispatchQueueはiOSおよびmacOSでの非同期タスクのためのGrand Central Dispatchの主要ツールです
  • シリアルキューはタスクを順次実行し、ロックなしで競合状態を排除します
  • コンカレントキューはシステムスレッドプールを介してタスクを並列実行します
  • QoSはタスクの優先順位を決定します — userInteractiveからbackgroundまで
  • DispatchGroupはメインスレッドでのnotifyを使用して複数の並列タスクを同期します
  • ビジーなシリアルキューでのsyncによるデッドロックは注意が必要な重大なエラーです
  • UIKitにはメインスレッドが必須です — DispatchQueue.mainを介してのみインターフェースを更新してください

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

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

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

こちらもお読みください