Javaのマルチスレッド設計ベストプラクティスの知識マップ(知識グラフ)
type: Dataset
description: Javaでは共有データの見え方がメモリモデルのhappens-before関係で定義されており、同期なしの共有変数は未定義動作にはならないものの、古い値が見え続けたり書き込みの順序が入れ替わって見えたりするメモリ一貫性エラーが正当に起こります。実務指針は、素の共有変数で工夫せずjava.util.concurrentの道具にhappens-beforeを作らせることです。スレッドはExecutorServiceに任せ、I/O待ちが主体のタスクはJDK 21で正式化された仮想スレッドへ、CPUバウンドはコア数程度のプラットフォームスレッドへ振り分けます。仮想スレッドはプールせず、同時実行数の制限はSemaphoreで表現します。JDK 21〜23のsynchronizedによるピン留めはJDK 24のJEP 491で解消されました。停止は割り込みによる協調停止が唯一の正解で、Thread.stopは現在UnsupportedOperationExceptionになります。
language: ja
creator: 合同会社小村ソフト
license: https://creativecommons.org/licenses/by/4.0/
is accessible for free: true
keywords: 共有可変状態
keywords: Javaメモリモデルとhappens-before
keywords: 競合状態(race condition)
keywords: デッドロック(deadlock)
keywords: メモリ一貫性エラー
keywords: volatile
keywords: ExecutorService
keywords: スレッドの自作(new Thread)
keywords: 仮想スレッド
keywords: プラットフォームスレッド
keywords: キャリアスレッドへのピン留め
keywords: Semaphoreによる同時実行数制限
keywords: backpressure
keywords: スレッドローカル状態
keywords: ConcurrentHashMap.computeIfAbsent
keywords: BlockingQueue
keywords: synchronizedブロック
keywords: ReentrantLock
keywords: 専用ロックオブジェクト
keywords: ロック取得順序の統一
keywords: Atomic系クラス(AtomicInteger / LongAdder)
keywords: 割り込み(interruption)
keywords: 協調キャンセル
keywords: Thread.stop / suspend / resume
keywords: ExecutorServiceの2段階シャットダウン
keywords: UIスレッドのコンテキスト
keywords: イベントディスパッチスレッド(EDT)
keywords: スレッドダンプ(jstack / jcmd)
keywords: 構造化並行性(StructuredTaskScope)
keywords: Scoped Values
keywords: happens-before関係
keywords: I/Oバウンドなタスク
keywords: CPUバウンドなタスク
keywords: 同時実行数の制限
keywords: 期限内の停止処理
distribution: DataDownload
  encoding format: application/ld+json
distribution: DataDownload
  encoding format: text/turtle
citation: https://docs.oracle.com/javase/tutorial/essential/concurrency/memconsist.html
citation: https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/util/concurrent/ExecutorService.html
citation: https://openjdk.org/jeps/444
citation: https://docs.oracle.com/en/java/javase/21/core/virtual-threads.html
citation: https://openjdk.org/jeps/491
citation: https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/util/concurrent/ConcurrentHashMap.html
citation: https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/lang/Thread.html
citation: https://docs.oracle.com/javase/tutorial/uiswing/concurrency/dispatch.html
citation: https://docs.oracle.com/en/java/javase/21/docs/specs/man/jstack.html
citation: https://openjdk.org/jeps/505
citation: https://openjdk.org/jeps/525
citation: https://openjdk.org/jeps/506
about: article

合同会社小村ソフト
type: Organization

共有可変状態
type: Concept
definition: 複数のスレッドから読み書きされる、書き換え可能なデータ。競合はこれと複数スレッドが揃ったときにだけ起きる。
may cause: 競合状態(race condition)
may cause: メモリ一貫性エラー

Javaメモリモデルとhappens-before
type: Concept
definition: 共有データの見え方を定める規則。あるステートメントによるメモリ書き込みが、別のステートメントから見えることを保証する関係をhappens-beforeという。
alternative label: JMM
alternative label: happens-before
uses: happens-before関係

競合状態(race condition)
type: Concept
definition: 複数のスレッドがどの順序で特定のコードに到達するかによって結果が変わってしまう不具合。
alternative label: レースコンディション

メモリ一貫性エラー
type: Concept
definition: 同じデータに対して複数のスレッドが一貫しない見え方をすることで生じる誤り。古い値が見え続けたり、書き込みの順序が入れ替わって見えたりする。

happens-before関係
type: Concept
definition: あるスレッドのメモリ書き込みが別スレッドの読み取りから見えることを保証する、Java言語仕様が定める順序関係。synchronized・volatile・java.util.concurrentの各機能が確立する。
prevents: メモリ一貫性エラー

volatile
type: Concept
definition: 最適化による読み書きの除去を抑える型修飾子。スレッド間の同期を保証するものではない。
not recommended for: 競合状態(race condition)

Atomic系クラス(AtomicInteger / LongAdder)
type: Concept
definition: 単一変数の原子的更新を提供するJavaのクラス群。LongAdderは内部でセルを分割して競合を散らす。
prevents: 競合状態(race condition)

ExecutorService
type: Concept
definition: 仕事(Runnable / Callable)と、それをどう実行するかを分離し、スレッドの生成・再利用・破棄をライブラリに任せるJavaの実行基盤。
succeeds: スレッドの自作(new Thread)

スレッドの自作(new Thread)
type: Concept
definition: 上位のAPIに任せず、スレッドオブジェクトを直接生成してライフサイクルを自分で管理する書き方。

backpressure
type: Concept
definition: 流し込みが速すぎるときに、書き込み側を待たせて増えすぎを防ぐ仕組み。
alternative label: バックプレッシャー

仮想スレッド
type: Concept
definition: Javaランタイムが実装する軽量スレッド。JDKのブロッキング操作の間はOSスレッドを手放すため、数百万本を1つのJVMで走らせられる。JDK 21で正式機能になった。
alternative label: Virtual Threads
not recommended for: CPUバウンドなタスク

I/Oバウンドなタスク
type: Concept
definition: 処理時間の大半がネットワークやディスクなどI/Oの完了待ちで占められるタスク。

CPUバウンドなタスク
type: Concept
definition: 処理時間の大半が計算で占められ、I/O待ちがほとんどないタスク。並列化の効果はコア数で頭打ちになる。

Semaphoreによる同時実行数制限
type: Concept
definition: 「外部APIへ同時10接続まで」のような制限を、プールのサイズではなくセマフォの許可数で表現する形。
recommended for: 同時実行数の制限

同時実行数の制限
type: Concept
definition: 外部APIやデータベースなどの資源に対して、同時に走る処理の数へ上限を設けること。

キャリアスレッドへのピン留め
type: Concept
definition: 仮想スレッドがブロックしてもキャリアとなるOSスレッドを手放せず、占有し続けてしまう状態。

synchronizedブロック
type: Concept
definition: Javaの組み込みモニターによる相互排他構文。ロック対象のオブジェクトを指定して排他区間を作る。
requires: 専用ロックオブジェクト

専用ロックオブジェクト
type: Concept
definition: 外部に公開しない、ロック専用のインスタンス。.NET 9 / C# 13以降はSystem.Threading.Lock型を使う。

ReentrantLock
type: Concept
definition: タイムアウト付き取得(tryLock)、公平性ポリシー、複数のConditionを扱えるJavaの明示的ロック。

ロック取得順序の統一
type: Concept
definition: 複数のロックを取るとき、全スレッドが同じ順序で取ると決めるルール。
prevents: デッドロック(deadlock)

デッドロック(deadlock)
type: Concept
definition: 複数のタスクが互いの完了やリソース解放を待ち続け、永遠に進行しなくなる状態である。
alternative label: Deadlock
verified by: スレッドダンプ(jstack / jcmd)

スレッドローカル状態
type: Concept
definition: 各スレッドが自分だけの領域に持つ中間状態。並列ループで共有メモリへ書き込まずに集計するために使う。

ConcurrentHashMap.computeIfAbsent
type: Concept
definition: キーが不在ならマッピング関数を呼んで値を登録する、呼び出し全体が原子的に実行されるメソッド。
prevents: 競合状態(race condition)

BlockingQueue
type: Concept
definition: 容量を指定できるJavaのブロッキングキュー。満杯時のputがブロックすることで背圧になる。
implements: backpressure

割り込み(interruption)
type: Concept
definition: 対象スレッドの割り込みステータスを立て、sleep・wait・joinでブロック中ならInterruptedExceptionで起こす、Javaの停止・キャンセルの共通言語。
implements: 協調キャンセル
succeeds: Thread.stop / suspend / resume

協調キャンセル
type: Concept
definition: キャンセルを強制ではなく要求として伝え、停止の仕方はリスナー側が決めるモデル。

Thread.stop / suspend / resume
type: Concept
definition: スレッドを外から強制的に止めようとした旧世代のAPI。不正な状態のままロックが解放されるなど本質的に安全でない。

ExecutorServiceの2段階シャットダウン
type: Concept
definition: shutdown()で新規受付を止めて完走を待ち、期限を過ぎたらshutdownNow()で停止を試みる停止手順。
uses: 割り込み(interruption)
recommended for: 期限内の停止処理

期限内の停止処理
type: Concept
definition: サービス停止やアプリ終了までの限られた時間内に、スレッドプールの停止を確実に完了させること。

イベントディスパッチスレッド(EDT)
type: Concept
definition: Swingのイベント処理コードが走る専有スレッド。ほとんどのSwingオブジェクトのメソッドはスレッドセーフではない。
alternative label: EDT
implements: UIスレッドのコンテキスト

UIスレッドのコンテキスト
type: Concept
definition: WinForms/WPFなどデスクトップアプリで、UIの応答性を保つために画面更新や重い処理の実行場所として意識されるコンテキスト。
alternative label: UIイベントハンドラ

スレッドダンプ(jstack / jcmd)
type: Concept
definition: 指定したJavaプロセスの全スレッドのスタックトレースを出力する標準ツール。-lでロックに関する追加情報も出せる。
not recommended for: 仮想スレッド

構造化並行性(StructuredTaskScope)
type: Concept
definition: 関連するサブタスク群を1つの作業単位として扱い、エラー伝播とキャンセルを構造化するJavaのAPI。

Scoped Values
type: Concept
definition: スレッド内およびスレッド間で不変のコンテキストデータを安全かつ効率的に共有する仕組み。ThreadLocalの可変性・寿命管理・継承コストへの解決策としてJDK 25で正式化された。
succeeds: スレッドローカル状態

subject: 共有可変状態
predicate: mayCause
object: 競合状態(race condition)
description: count++は読み込み・加算・書き戻しの3ステップに分かれるため、2つのスレッドが同時に入ると一方の加算が上書きされて消える。
evidence: memconsist.html
verified at: 2026-08-02
certainty: established

subject: 共有可変状態
predicate: mayCause
object: メモリ一貫性エラー
description: 同期なしに共有変数を読み書きすると、同じデータに対して複数のスレッドが一貫しない見え方をする。ループの中でbooleanフラグを見ているのに他スレッドが変えた値がいつまでも見えない、という現象はメモリモデルが許す動作でJVMのバグではない。
evidence: memconsist.html
verified at: 2026-08-02
certainty: established

subject: Javaメモリモデルとhappens-before
predicate: uses
object: happens-before関係
description: Javaメモリモデルはhappens-before関係によって、あるステートメントによるメモリ書き込みが別のステートメントから見えることを定義する。
evidence: memconsist.html
verified at: 2026-08-22
certainty: established

subject: happens-before関係
predicate: prevents
object: メモリ一貫性エラー
description: メモリ一貫性エラーを避ける鍵はhappens-before関係を正しく作ることで、synchronized・volatile・java.util.concurrentの各クラスがこの関係を確立する。同期なしではメモリモデルは古い値や並べ替えられた観測を許す。
evidence: memconsist.html
verified at: 2026-08-22
certainty: established

subject: volatile
predicate: notRecommendedFor
object: 競合状態(race condition)
description: volatileは可視性と順序(happens-before)の保証であって、複合操作の原子性は与えない。フラグと単一値はAtomic系、複合状態はロックにする。
evidence: memconsist.html
verified at: 2026-08-02
certainty: established

subject: Atomic系クラス(AtomicInteger / LongAdder)
predicate: prevents
object: 競合状態(race condition)
description: 単一変数の原子的更新はAtomicInteger / AtomicLong / AtomicReferenceが受け持ち、高頻度に加算するだけの統計値なら競合に強いLongAdderを使う。
evidence: memconsist.html
verified at: 2026-08-02
certainty: established

subject: ExecutorService
predicate: succeeds
object: スレッドの自作(new Thread)
description: 仕事(Runnable / Callable)と、それを何本のスレッドでどのキューで実行するかを分離し、スレッドの生成・再利用・破棄をライブラリに任せる。
evidence: ExecutorService.html
verified at: 2026-08-02
certainty: established

subject: ExecutorService
predicate: requires
object: backpressure
description: 固定プールはスレッド数を制限するが待ち行列は無制限なので、投入が処理を上回り続ける常駐サービスではキューに積まれたタスクがメモリを食い続ける。容量付きキューと拒否ポリシー、または投入側の入場制限で背圧をかける。
evidence: ExecutorService.html
verified at: 2026-08-02
certainty: context-dependent

subject: 仮想スレッド
predicate: recommendedFor
object: I/Oバウンドなタスク
description: JDKのブロッキング操作の間はOSスレッドを手放すため、I/O待ちが主体のタスクは「タスク1つに仮想スレッド1本」で走らせる。newVirtualThreadPerTaskExecutorの形で使い、決してプールしない。
evidence: https://openjdk.org/jeps/444
evidence: virtual-threads.html
verified at: 2026-08-22
certainty: context-dependent

subject: 仮想スレッド
predicate: notRecommendedFor
object: CPUバウンドなタスク
description: 仮想スレッドは速いスレッドではなくスケール(スループット)のための機能で、コードの実行速度は変わらない。CPUバウンドの並列化は従来どおりコア数程度のプラットフォームスレッドが適任である。
evidence: virtual-threads.html
verified at: 2026-08-22
certainty: established

subject: Semaphoreによる同時実行数制限
predicate: recommendedFor
object: 同時実行数の制限
description: 「外部APIへ同時10接続まで」のような同時実行数の制限は、プールのサイズではなくSemaphoreで表現する。
evidence: virtual-threads.html
verified at: 2026-08-22
certainty: established

subject: 仮想スレッド
predicate: mayCause
object: キャリアスレッドへのピン留め
description: JDK 21〜23ではsynchronizedブロック・メソッド内でブロックすると仮想スレッドがキャリアスレッドにピン留めされ、スケールの利点が失われる制約があった。
evidence: https://openjdk.org/jeps/491
evidence: virtual-threads.html
verified at: 2026-08-02
certainty: context-dependent

subject: synchronizedブロック
predicate: incompatibleWith
object: キャリアスレッドへのピン留め
description: JDK 24でJVMのモニター実装が仮想スレッド対応に書き直され、synchronizedブロック・メソッド内でブロックしても仮想スレッドがピン留めされなくなった。ピン留め対策としての機械的なReentrantLockへの置き換えは不要になっている。
evidence: https://openjdk.org/jeps/491
verified at: 2026-08-22
certainty: context-dependent

subject: synchronizedブロック
predicate: requires
object: 専用ロックオブジェクト
description: synchronized(this)やsynchronized(SomeClass.class)は外部のコードが同じオブジェクトをロックできてしまうため、外部に公開しないprivate finalのロックオブジェクトを守りたいデータと1対1で対応させる。
evidence: https://openjdk.org/jeps/491
verified at: 2026-08-02
certainty: established

subject: ReentrantLock
predicate: succeeds
object: synchronizedブロック
description: タイムアウト付き取得(tryLock)、公平性ポリシー、複数のCondition、ロックの取得と解放を別メソッドに分けたい場合はReentrantLockに進む。lock()の直後にtry、finallyでunlock()という形を崩さない。
evidence: virtual-threads.html
verified at: 2026-08-02
certainty: context-dependent

subject: ロック取得順序の統一
predicate: prevents
object: デッドロック(deadlock)
description: 2つ以上のロックを取る場所では全スレッドが同じ順序で取ることをルール化し、順序を保証できない箇所にはtryLock(timeout)で取れなければ手放してやり直す経路を用意する。
evidence: virtual-threads.html
verified at: 2026-08-02
certainty: established

subject: スレッドローカル状態
predicate: mitigates
object: 共有可変状態
description: 並列集計では共有の合計変数に各スレッドが書き込むのではなく、スレッドごとに部分結果を作って最後に合流させる。LongAdderも内部でセルを分割して競合を散らし、読むときに合算する実装である。
evidence: memconsist.html
verified at: 2026-08-22
certainty: context-dependent

subject: ConcurrentHashMap.computeIfAbsent
predicate: prevents
object: 競合状態(race condition)
description: computeIfAbsentはメソッド呼び出し全体が原子的に実行され、キー不在時にマッピング関数がその1回の呼び出しの中でちょうど1回だけ呼ばれる。原子的である代償として計算中は他スレッドの一部の更新がブロックされるため、マッピング関数は短く保ち、関数の中でこのマップ自体を更新してはいけない。
evidence: ConcurrentHashMap.html
verified at: 2026-08-02
certainty: established

subject: BlockingQueue
predicate: implements
object: backpressure
description: 容量を指定したArrayBlockingQueueなら、満杯時にputがブロックして自然な背圧になる。プロデューサー/コンシューマーの境界を明確にするこの設計は仮想スレッド時代でも有効である。
evidence: ExecutorService.html
verified at: 2026-08-02
certainty: established

subject: 割り込み(interruption)
predicate: implements
object: 協調キャンセル
description: interrupt()は対象スレッドの割り込みステータスを立て、sleep・wait・joinなどでブロックしていればInterruptedExceptionを投げて即座に起こす(このときステータスはクリアされる)。InterruptedExceptionをcatchして何もしないコードを書かず、終了できないならステータスを復元して呼び出し元へ合図を伝える。
evidence: Thread.html
verified at: 2026-08-02
certainty: established

subject: 割り込み(interruption)
predicate: succeeds
object: Thread.stop / suspend / resume
description: Thread.stop / suspend / resumeは、不正な状態のままロックが解放されて壊れたオブジェクトが見えたり、suspendがデッドロックを招いたりするため本質的に安全でなく、現在は呼ぶとUnsupportedOperationExceptionになる。
evidence: Thread.html
verified at: 2026-08-02
certainty: established

subject: ExecutorServiceの2段階シャットダウン
predicate: uses
object: 割り込み(interruption)
description: shutdown()は投入済みタスクを完走させつつ新規受付を止め、shutdownNow()は実行中タスクの停止を試みる。これはベストエフォートで、典型的な実装はThread.interrupt()でキャンセルするため、割り込みに応答しないタスクはshutdownNowでも止まらない。
evidence: ExecutorService.html
verified at: 2026-08-02
certainty: established

subject: ExecutorServiceの2段階シャットダウン
predicate: recommendedFor
object: 期限内の停止処理
description: 公式ドキュメントが示す停止の定石は、shutdown → awaitTermination → shutdownNow の2段階パターンである。JDK 19以降のclose()はタイムアウトなしで完了を待つため、必ず有限時間で終えたい停止経路には期限付きの2段階パターンを使う。
evidence: ExecutorService.html
verified at: 2026-08-22
certainty: established

subject: イベントディスパッチスレッド(EDT)
predicate: implements
object: UIスレッドのコンテキスト
description: Swingのイベント処理コードはEDT上で走り、ほとんどのSwingオブジェクトのメソッドはスレッドセーフではないため、複数スレッドから触るとスレッド干渉やメモリ一貫性エラーを招く。別スレッドからの画面更新はSwingUtilities.invokeLaterでEDTに依頼する。
evidence: dispatch.html
verified at: 2026-08-22
certainty: established

subject: デッドロック(deadlock)
predicate: verifiedBy
object: スレッドダンプ(jstack / jcmd)
description: jstack(またはjcmd Thread.print)が全スレッドのスタックトレースを出力し、-lでロックに関する追加情報まで表示できる。ダンプを数秒おきに2〜3回取り、動いていないスレッドがどのロックを待ち、そのロックを誰が握っているかを突き合わせる。
evidence: jstack.html
verified at: 2026-08-02
certainty: established

subject: スレッドダンプ(jstack / jcmd)
predicate: notRecommendedFor
object: 仮想スレッド
description: 従来形式のスレッドダンプはプラットフォームスレッド向けで、アプリの仮想スレッドは含まれない。仮想スレッドを使う構成では jcmd Thread.dump_to_file -format=json を使う。
evidence: https://openjdk.org/jeps/444
verified at: 2026-08-22
certainty: established

subject: 構造化並行性(StructuredTaskScope)
predicate: uses
object: 仮想スレッド
description: 構造化並行性APIは関連するサブタスク群を1つの作業単位として扱い、エラー伝播とキャンセルを構造化する。JDK 25の第5次プレビューでStructuredTaskScope.open()の形に改められ、JDK 26でも第6次プレビューとして継続しているため、利用にはプレビュー機能の有効化が必要になる。
evidence: https://openjdk.org/jeps/505
evidence: https://openjdk.org/jeps/525
verified at: 2026-08-02
certainty: context-dependent

subject: Scoped Values
predicate: succeeds
object: スレッドローカル状態
description: Scoped ValuesはJDK 25で正式化され、スレッド内およびスレッド間で不変のコンテキストデータを安全かつ効率的に共有する。ThreadLocalの可変性・寿命管理・継承コストへの解決策として位置づけられている。
evidence: https://openjdk.org/jeps/506
verified at: 2026-08-02
certainty: established