IntelliJ IDEA 2026.1 Help

非同期コードをデバッグする

非同期コードのデバッグは、タスクが 1 つのスレッドでスケジュールされ、別のスレッドで実行されることが多いため、困難です。 各スレッドには独自のスタックトレースが存在するため、スレッドの開始前に何が起こったかを把握することが困難です。

IntelliJ IDEA は、異なるスレッドのフレーム間の接続を確立することにより、それを容易にします。 これにより、ワーカースレッドからタスクがスケジュールされた場所までさかのぼって、実行がすべて同じスレッド内にあるかのようにプログラムをデバッグできます。

非同期スタックトレースを試すには、次の例をデバッグします。

import java.util.*; import java.util.concurrent.*; public class AsyncExample { static List<Task> tasks = new ArrayList<>(); static ExecutorService executor = Executors.newScheduledThreadPool(4); public static void main(String[] args) { createTasks(); executeTasks(); } private static void createTasks() { for (int i = 0; i < 20; i++) { tasks.add(new Task(i)); } } private static void executeTasks() { for (Task task : tasks) { executor.submit(task); } } static class Task extends Thread { int num; public void run() { try { Thread.sleep(new Random().nextInt(2000)); } catch (InterruptedException e) { e.printStackTrace(); } printNum(); } private void printNum() { // Set a breakpoint at the following line System.out.print(num + " "); } public Task(int num) { this.num = num; } } }

printNum() メソッドのブレークポイントで停止すると、2 つのスタックトレースが利用できます。

  • 現在のスレッド (ワーカー)

  • メインスレッド (タスクがスケジュールされた場所)

Threads タブでは、スタックトレースの 2 つの部分が表示されます。1 つはワーカースレッド用、もう 1 つはスケジューリングスレッド用です。

コンソールの非同期スタックトレース

デフォルトでは、コードをデバッグしたり、 JUnit/TestNG ユニットテストを実行したりすると、非同期スタックトレースがコンソールに表示されます。

失敗したテストのコンソールに出力される非同期スタックトレース

対応する実行構成で 例外の非同期スタックトレースを印刷する チェックボックスをオフにすると、テストの非同期スタックトレースを無効にすることができます。

実行構成の「例外の非同期スタックトレースを印刷する」チェックボックスダイアログ

デバッグセッションの非同期スタックトレースをオンまたはオフにするには、 設定 | ビルド、実行、デプロイ | デバッガー | 非同期スタックトレースインストゥルメントエージェント オプションを使用します。

非同期アノテーション

非同期スタックトレースは、Swing および Java Concurrency API ですぐに使用できますが、独自のカスタムクラスで使用できるように手動で拡張することもできます。 これは、特別なアノテーションを使用して行われます。

アノテーションは、キャプチャーポイントと挿入ポイントを定義するために使用されます。

  • キャプチャーポイントは、スタックトレースがキャプチャーされる方法です。 キャプチャーポイントでは、スタックトレースが保存され、キーが割り当てられます。 キャプチャーポイントには @Async.Schedule アノテーションが付けられています。

  • 挿入ポイントは、以前に保存されたスタックトレースの 1 つが現在のスタックにアタッチされるメソッドです。 挿入ポイントには、 @Async.Execute アノテーションが付けられます。

  • キーは、キャプチャーされたスタックトレースの一意の識別子として機能するパラメーターまたはオブジェクト参照です。 非同期スタックトレースの各部分を一致させるために必要です。

キャプチャーポイントと挿入ポイントを定義する

メソッドまたはそのパラメーターにアノテーションを付けることができます。

  • オブジェクト参照 (this) をキーとして使用する場合は、メソッド自体にアノテーションを付けます。例:

    @Async.Schedule private static void schedule(Integer i) { System.out.println("Scheduling " + i); queue.put(i); }
  • パラメーター値をキーとして使用する場合は、メソッドパラメーターにアノテーションを付けます。例:

    private static void schedule(@Async.Schedule Integer i) { System.out.println("Scheduling " + i); queue.put(i); }

アノテーションがどのように機能するかをテストするには、次の例を使用できます。

import org.jetbrains.annotations.Async; import java.util.concurrent.*; public class AsyncSchedulerExample { private static final BlockingQueue<Integer> queue = new LinkedBlockingQueue<>(); public static void main(String[] args) throws InterruptedException { new Thread(() -> { try { while (true) { process(queue.take()); } } catch (InterruptedException e) { e.printStackTrace(); } }).start(); schedule(1); schedule(2); schedule(3); } private static void schedule(@Async.Schedule Integer i) throws InterruptedException { System.out.println("Scheduling " + i); queue.put(i); } private static void process(@Async.Execute Integer i) { // Set a breakpoint at the following line System.out.println("Processing " + i); } }

カスタムアノテーションを定義する

プロジェクトに JetBrains アノテーションの依存関係を追加したくない場合は、独自のアノテーションを定義して、デフォルトのアノテーションの代わりに使用することができます。

  1. キャプチャーポイントと挿入ポイントに独自のアノテーションを作成します。 参考として、 Async.java(英語) を参照してください。

  2. Ctrl+Alt+S を押して設定を開き、 ビルド | 実行 | デプロイ | デバッガー | 非同期スタックトレース を選択します。

  3. アノテーションの構成 をクリックします。

  4. 非同期アノテーションの構成 ダイアログで、 追加 をクリックして、カスタムアノテーションを 非同期スケジュールアノテーション および 非同期アノテーションを実行する に追加します。

詳細な構成

アノテーションベースのアプローチは、計測エージェントに依存しており、ほとんどの場合に機能します。 すべての作業をデバッガーだけに委譲する方法があります。 これは、次の場合に必要になることがあります。

  • ローカル変数をキャプチャーする必要がある

  • アノテーションを使用できません

  • 計装エージェントを使用できません

内部的には、このアプローチはアノテーションの代わりに非表示のブレークポイントを使用します。 このような非表示のブレークポイントに到達すると、指定された式が評価され、その結果が非同期スタックトレースの各部分と一致するために使用されます。

柔軟性とパフォーマンスの間にはトレードオフがあります。 このオプションは、パフォーマンスが重要な高度な並行プロジェクトには推奨されません。

  1. Ctrl+Alt+S を押して設定を開き、 ビルド | 実行 | デプロイ | デバッガー | 非同期スタックトレース を選択します。

  2. 追加 をクリックして、次の情報を入力します。

    • キャプチャークラス名: スタックトレースをキャプチャーする必要があるクラスの完全修飾名(javax.swing.SwingUtilities など)

    • キャプチャーメソッド名: パラメーターリストと括弧を含まないメソッド名(例: invokeLater

    • キャプチャーキー式 :結果が鍵として使用される式です。 式では、フレームのコンテキストで到達可能なすべてのものを使用することができます。 メソッドパラメーターは param_N のように指定できます。ここで N はパラメーターの 0 始まりの番号であり、例えば param_0 です。

    • 挿入クラス名: スタックトレースが一致する必要があるクラスの完全修飾名(java.awt.event.InvocationEvent など)

    • 挿入メソッド名: パラメーターリストと括弧を含まないメソッド名(例: dispatch

    • 挿入キー式 :結果が鍵として使用される式です。 式では、フレームのコンテキストで到達可能なすべてのものを使用することができます。 メソッドパラメーターは param_N のように指定できます。ここで N はパラメーターの 0 始まりの番号であり、例えば param_0 です。

  3. (オプション)ローカル変数(呼び出しスタックと一緒にプリミティブと文字列値)もキャプチャーする場合は、 ローカル変数をキャプチャーする オプションを選択します。 これにより、デバッグプロセスが遅くなる可能性があることに注意してください。

次のリポジトリから追加のキャプチャー設定をダウンロードできます: IntelliJ IDEA デバッガーのキャプチャーポイント (英語)

リモート JVM で非同期スタックトレースを表示する

たとえば、 Docker コンテナー内で管理されているリモートプロセスをデバッグしている場合でも、JVM インストルメンティングエージェントを使用して、IDE から開始されたかのように非同期スタックトレースを表示できます。

リモートでエージェントを使用するには、次の手順を実行します。

  • <IDEA インストールフォルダー> /lib/rt/debugger-agent.jar をリモートマシン上の任意の場所にコピーします

  • -javaagent:<path to debugger-agent.jar> をリモート JVM オプションに追加する

2026 年 3 月 30 日