The English version of quarkus.io is the official project site. Translated sites are community supported on a best-effort basis.
このページを編集

仮想スレッドサポートリファレンス

このガイドでは、QuarkusアプリケーションでJava 21+の仮想スレッドを使用する方法について説明します。

仮想スレッドとは?

用語解説

OS スレッド

オペレーティングシステムによって管理される「スレッドのような」データ構造。

プラットフォームスレッド

Java 19 までは、スレッド クラスのインスタンスはすべて、OS スレッドのラッパーであるプラットフォームスレッドでした。 プラットフォームスレッドを作成すると OS スレッドが作成され、プラットフォームスレッドがブロックされると OS スレッドもブロックされます。

仮想スレッド

軽量で、JVM が管理するスレッド。スレッド クラスを拡張していますが、1 つの特定の OS スレッドに関連付けられていません。 したがって、仮想スレッドのスケジューリングは JVM の責任となります。

キャリアースレッド

仮想スレッドを実行するために使用されるプラットフォームスレッドは、キャリアースレッド と呼ばれます。 これは スレッド または VirtualThread とは異なるクラスではなく、機能的な呼称です。

仮想スレッドとプラットフォームスレッドの違い

ここでは、このトピックに関する概要を説明しますが、詳細は JEP 425 を参照してください。

仮想スレッドは、Java 19 から利用可能な機能で (Java 21 は、仮想スレッドを含む最初の LTS バージョン)、 I/O バウンドのワークロードに対して、プラットフォームスレッドの安価な代替を提供することを目的としています。

これまで、プラットフォームスレッドが JVM の同時実行ユニットでした。 スレッドは、OS 構造体のラッパーです。 Java プラットフォームスレッドを作成すると、オペレーティングシステムに「スレッドのような」構造が作成されます。

一方、仮想スレッドは JVM によって管理されます。実行するには、(その仮想スレッドのキャリアーとして機能する) プラットフォームスレッドにマウントする必要があります。 そのため、以下のような特徴があります。

軽量

仮想スレッドは、プラットフォームスレッドよりもメモリー上の占有領域が小さくなります。 したがって、メモリーを消費することなく、プラットフォームスレッドよりも多くの仮想スレッドを同時に使用することが可能になります。 デフォルトでは、プラットフォームスレッドは約 1MB のスタックで作成されますが、仮想スレッドのスタックは "pay-as-you-go "です。 Loom プロジェクト (JVM に仮想スレッドサポートを追加したプロジェクト) のリード開発者が行った プレゼンテーション で、これらの数字や仮想スレッドの他の動機を見つけることができます。

作成が安価

Java でプラットフォームスレッドを作成するには時間がかかります。 現在では、スレッドを一度作成してから再利用するプーリングのようなテクニックが、スレッドの起動にかかる時間のロスを最小限に抑えるために強く推奨されています (同様に、メモリー消費量を低く抑えるためにスレッドの最大数を制限することも推奨されています)。 仮想スレッドは必要なときに作成する使い捨てのものであり、 スレッドをプールしたり別のタスクに再利用したりすることは推奨されません。

安価なブロック

ブロッキング I/O を実行するとき、Java プラットフォームのスレッドによってラップされた基礎となる OS スレッドは待ち行列に入れられ、新しいスレッドコンテキストを CPU コアにロードするためにコンテキストスイッチが発生します。 この操作には時間がかかります。JVM は仮想スレッドを管理するため、OS スレッドがブロッキング操作を実行しても、そのスレッドがブロックされることはありません。 それらの状態はヒープに格納され、別の仮想スレッドが同じ Java プラットフォーム (キャリアー) スレッド上で実行されます。

継続的な動作

前述のように、JVM は仮想スレッドをスケジュールします。これらの仮想スレッドはキャリアースレッドにマウントされます。このスケジューリングには少し魔法のような仕組みがあります。仮想スレッドがブロッキング I/O を使用しようとすると、JVM はこの呼び出しをノンブロッキングの呼び出しに 変換 し、仮想スレッドをアンマウントして、別の仮想スレッドをキャリアースレッドにマウントします。I/O が完了すると、待機していた 仮想スレッドが再び実行可能な状態になり、再びキャリアースレッドにマウントされて処理を続行します。ユーザーからは、この一連の動作はすべて見えません。同期コードは非同期で実行されます。

仮想スレッドを同じキャリアースレッドに再マウントすることはできません。

仮想スレッドはI/Oバウンドワークロードにのみに有効

私たちは、プラットフォームスレッドよりも多くの仮想スレッドを作成できることを理解しました。このため、長時間の計算 (CPU バウンドワークロード) をするために仮想スレッドを使用したいと考えるかもしれません。 しかし、これは無意味であり、逆効果です。 CPU バウンド処理は、I/O の完了を待つ間にスレッドをすばやく切り替えるのではなく、 スレッドを CPU コアにアタッチして何らかの計算を行うものです。 このようなケースでは、数十個の CPU コアに対して数千個のスレッドを持つことは非常に無意味で、仮想スレッドが CPU バウンドワークロードのパフォーマンスを向上させることはありません。 それどころか、仮想スレッド上で CPU バウンドワークロードを実行すると、仮想スレッドがマウントされているキャリアースレッドをその仮想スレッドが独占してしまいます。 その結果、他の仮想スレッドが実行される機会が減るか、新しいキャリアースレッドが次々に作成されることになり、メモリー使用量が増大してしまいます。

@RunOnVirtualThread を使用した仮想スレッド上でのコード実行

Quarkus では、仮想スレッドのサポートは @RunOnVirtualThread アノテーションを使用して実装されています。 このセクションでは、その論理的根拠と使い方について簡単に説明します。 このアノテーションをサポートするエクステンションには、以下のような専用のガイドも用意されています。

すべてを仮想スレッドで実行しない理由

前述したように、すべてが仮想スレッド上で安全に実行できるわけではありません。 独占 のリスクはメモリー使用量の多さにつながります。 また、仮想スレッドをキャリアースレッドからアンマウントできない状況もあります。 これは ピニング と呼ばれます。 最後に、一部のライブラリーは ThreadLocal を使用してオブジェクトを保存し再利用します。 これらのライブラリーで仮想スレッドを使用すると、意図的にプールされたオブジェクトが (使い捨てで一般に短命な) 仮想スレッドごとにインスタンス化されるため、大量の割り当てが発生します。

現在のところ、仮想スレッドを自由に使うことはできません。 このような自由放任のアプローチをとると、すぐにメモリやリソースの枯渇という問題が発生します。 そのため Quarkus では、前述の問題がなくなるまで (Javaエコシステムが成熟するまで) 明示的なモデルを使用します。 リアクティブ エクステンションが仮想スレッドをサポートし、古典的な スレッドをほとんどサポートしない理由もここにあります。 仮想スレッドでディスパッチするタイミングを知る必要があります。

これらの問題は、Quarkusの制限やバグではなく、仮想スレッドフレンドリーに進化する必要があるJavaエコシステムの現状によるものであることを理解することが重要です。

内部設計と選択の詳細については、Considerations for integrating virtual threads in Java framework: a Quarkus example in resource-constrained environment を参照してください。

独占の場合

独占については、仮想スレッドは I/O バウンドのワークロードにのみ有効 のセクションで説明しました。 長い計算を実行する場合、仮想スレッドが終了するまで、JVM がアンマウントして別の仮想スレッドに切り替えることを許可しません。 実際、現在のスケジューラはタスクのプリエンプトをサポートしていません。

この独占は、他の仮想スレッドを実行するために新しいキャリアースレッドを作成することにつながります。 キャリアースレッドを作成すると、プラットフォームスレッドを作成することになります。 そのため、この作成にはメモリーコストがかかります。

コンテナーのような制約のある環境で実行するとします。その場合、メモリー使用量の多さがメモリ不足の問題やコンテナーの終了につながる可能性があるため、独占はすぐに懸念事項となります。 メモリー使用量は、スケジューリングと仮想スレッドに固有のコストがかかるため、通常のワーカースレッドよりも高くなる可能性があります。

ピニングの場合

「安価なブロッキング」の約束は常に成り立つわけではありません。仮想スレッドは特定の状況でそのキャリアーを ピン することがあります。 この場合、プラットフォームスレッドはブロックされ、通常のブロッキングシナリオと同様に動作します。

JEP 425 によると、これは次の 2 つの状況で発生する可能性があります。

  • 仮想スレッドが synchronized ブロックまたはメソッドの内部でブロッキング操作を実行する場合

  • ネイティブメソッドや外部関数内でブロッキング操作を実行した場合

コード内でこのような状況を回避するのは比較的簡単ですが、使用する依存関係をすべて検証することは困難です。 通常、仮想スレッドを試している際に、postgresql-JDBC driver の 42.6.0 より古いバージョンでは、頻繁にピニングが発生することがわかりました。 ほとんどの JDBC ドライバーは、引き続きキャリアースレッドをピン留めします。 さらに悪いことに、多くのライブラリーではコードの変更が必要になります。

詳細は、When Quarkus meets Virtual Threads を参照してください。

このピンニングのケースに関する情報は、PostgreSQL JDBC ドライバー 42.5.4 以前に適用されます。 PostgreSQL JDBC ドライバー 42.6.0 以降では、事実上すべての同期されたメソッドが再入可能ロックに置き換えられています。 詳細は、PostgreSQL JDBC ドライバー 42.6.0 の Notable Changes を参照してください。

プーリングの場合

一部のライブラリーは、オブジェクトプーリングメカニズムとして ThreadLocal を使用しています。 Jackson および Netty などの非常に人気の高いライブラリーは、アプリケーションが限られた数のスレッドを使用し、それらのスレッドが (スレッドプールを使用して) リサイクルされて、複数の (無関係だが連続した) タスクを実行することを前提としています。

このパターンには、次のような複数の利点があります。

  • 割り当ての利点: 重いオブジェクトはスレッドごとに 1 回だけ割り当てられますが、これらのスレッドの数は制限されることが意図されているため、メモリーがあまり使用されません。

  • スレッドの安全性: スレッドローカルに格納されたオブジェクトにアクセスできるのは 1 つのスレッドのみであり、同時アクセスを防止します。

ただし、このパターンは仮想スレッドを使用する場合には逆効果になります。 仮想スレッドはプールされず、一般的に短命です。 そのため、少数のスレッドを使用するのではなく、大量のスレッドを扱うことになります。 それぞれのスレッドに対して、 ThreadLocal に格納されるオブジェクトが作成されます (多くの場合、サイズが大きく、コストもかかります)。しかし、仮想スレッドはプールされず (実行が完了した後に別のタスクを実行することもないため)、これらのオブジェクトは再利用されません。 この問題により、メモリー使用量が増加します。 残念ながら、この問題を解決するには、ライブラリー自体に高度なコード変更が必要になります。

Quarkus REST (旧 RESTEasy Reactive) で @RunOnVirtualThread を使用する

このセクションでは、@RunOnVirtualThread アノテーションの簡単な使用例を紹介します。 また、Quarkus が提供するさまざまな開発モデルと実行モデルについても説明します。

@RunOnVirtualThread アノテーションは、Quarkusに対して、現在のスレッドではなく 新しい 仮想スレッドでアノテーションされたメソッドを呼び出すように指示します。 Quarkusは仮想スレッドの作成とオフロードを処理します。

仮想スレッドは使い捨てのエンティティーであるため、 @RunOnVirtualThread の基本的な考え方は、エンドポイントハンドラーの実行をイベントループやワーカースレッド (Quarkus REST の場合) で実行する代わりに、新しい仮想スレッド上でオフロードすることです。

そのためには、エンドポイントに @RunOnVirtualThread アノテーションを追加すれば十分です。 アプリケーションの 実行 に使用される Java 仮想マシンが仮想スレッドのサポートを提供している場合 (Java 21 以降のバージョン)、エンドポイントの実行は仮想スレッドにオフロードされます。 これにより、仮想スレッドがマウントされているプラットフォームスレッドをブロックすることなく、ブロッキング処理を実行できるようになります。

Quarkus REST の場合、このアノテーションは、@Blocking のアノテーションが付与されたエンドポイント、 またはそのシグネチャーによりブロッキングと見なされるエンドポイントでのみ使用できます。 詳細は、実行モデル、ブロッキング、ノンブロッキング を参照してください。

Quarkus REST で仮想スレッドを使い始める

ビルドファイルに以下の依存関係を追加します。

pom.xml
<dependency>
    <groupId>io.quarkus</groupId>
    <artifactId>quarkus-rest</artifactId>
</dependency>
build.gradle
implementation("io.quarkus:quarkus-rest")

次に、Java 21 以降を使用していることも確認する必要があります。これは、pom.xml ファイルで次のように強制できます。

pom.xml
<properties>
    <maven.compiler.source>21</maven.compiler.source>
    <maven.compiler.target>21</maven.compiler.target>
</properties>

3 つの開発および実行モデル

以下の例は、3 つのエンドポイントの違いを示しています。これらのエンドポイントはすべて、データベース上の 財産 を照会し、 それをクライアントに返します。

  • 1 つ目は伝統的なブロッキングスタイルを採用しており、そのシグネチャーからブロッキングとみなされます。

  • 2 つ目は Mutiny を使用し、そのシグネチャーによりノンブロッキングとみなされます。

  • 3 つ目は Mutiny を使用しますが、同期的な方法で使用し、"reactive type" を返さないので、ブロッキングとみなされ、 @RunOnVirtualThread アノテーションを使用できます。

package org.acme.rest;

import org.acme.fortune.model.Fortune;
import org.acme.fortune.repository.FortuneRepository;
import io.smallrye.common.annotation.RunOnVirtualThread;
import io.smallrye.mutiny.Uni;

import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
import java.util.List;
import java.util.Random;


@Path("")
public class FortuneResource {

    @Inject FortuneRepository repository;

    @GET
    @Path("/blocking")
    public Fortune blocking() {
        // Runs on a worker (platform) thread
        var list = repository.findAllBlocking();
        return pickOne(list);
    }

    @GET
    @Path("/reactive")
    public Uni<Fortune> reactive() {
        // Runs on the event loop
        return repository.findAllAsync()
                .map(this::pickOne);
    }

    @GET
    @Path("/virtual")
    @RunOnVirtualThread
    public Fortune virtualThread() {
        // Runs on a virtual thread
        var list = repository.findAllAsyncAndAwait();
        return pickOne(list);
    }

}

以下の表は各選択肢の概要です。

モデル シグネチャーの例 長所 短所

同期コードでワーカースレッド上

Fortune blocking()

シンプルなコード

ワーカースレッドを使用 (同時実行に制限)

リアクティブコードでイベントループ上

Uni<Fortune> reactive()

高い同時実行性と低いリソース使用量

より複雑なコード

同期コードで仮想スレッド上

@RunOnVirtualThread Fortune vt()

シンプルなコード

ピニング、独占、効率の悪いオブジェクトプーリングのリスク

この 3 つのモデルすべてを 1 つのアプリケーションで使用できます。

仮想スレッドフレンドリーなクライアントの使用

すべてを仮想スレッドで実行しない理由 セクションで述べたように、Java エコシステムは仮想スレッドに完全には対応していません。 したがって、特に I/O を実行するライブラリーを使用する場合は注意が必要です。

幸いなことに、Quarkus は仮想スレッドですぐに使用できる大規模なエコシステムを提供しています。 Quarkus で使用されるリアクティブプログラミングライブラリーである Mutiny と Vert.x Mutiny バインディングは、キャリアースレッドをピン留めしないブロッキングコード (したがって、恐れる必要はなく、学習曲線もありません) を記述する機能を提供します。

上記の結果として、以下のようになります。

  1. リアクティブ API の上にブロッキング API を提供する Quarkus エクステンションは、仮想スレッドで使用できます。 これには、REST Client、Redis クライアント、メーラーなどが含まれます。

  2. Uni を返す API は、 uni.await().atMost(…​) を使用して直接使用できます。これは、キャリアースレッドをブロックせずに仮想スレッドをブロックし、簡単な (非ブロッキング) タイムアウトサポートによってアプリケーションの耐障害性も向上させます。

  3. Mutiny バインディングを使用する Vert.x クライアント を使用する場合は、キャリアースレッドをピニングせずに結果を取得するまでブロックする andAwait() メソッドを使用します。これには、すべてのリアクティブ SQL ドライバーが含まれます。

テストでピン留めされたスレッドを検出する

仮想スレッドを使用するアプリケーションでテストを実行する場合は、以下の設定を使用することを推奨します。 テストが失敗することはありませんが、コードがキャリアースレッドをピン留めした場合は、少なくともスタートトレースをダンプします:

<plugin>
  <artifactId>maven-surefire-plugin</artifactId>
  <version>${surefire-plugin.version}</version>
  <configuration>
      <systemPropertyVariables>
        <java.util.logging.manager>org.jboss.logmanager.LogManager</java.util.logging.manager>
        <maven.home>${maven.home}</maven.home>
      </systemPropertyVariables>
      <argLine>-Djdk.tracePinnedThreads</argLine>
  </configuration>
</plugin>

仮想スレッドを使用したアプリケーションの実行

java -jar target/quarkus-app/quarkus-run.jar
Java 21 以前では、仮想スレッドはまだ実験的な機能であったため、 --enable-preview フラグを付けてアプリケーションを起動する必要があります。

仮想スレッドを使用したアプリケーションのコンテナーのビルド

アプリケーションを JVM モードで実行する場合 (つまりネイティブにコンパイルしない場合、ネイティブについては 専用のセクション を参照してください)、コンテナー化ガイド に従ってコンテナーをビルドすることができます。

このセクションでは、JIB を使用してコンテナーをビルドします。 他の方法については、 コンテナー化ガイド を参照してください。

@RunOnVirtualThread を使用する Quarkus アプリケーションをコンテナー化するには、 application.properties に以下のプロパティーを追加します。

quarkus.container-image.build=true
quarkus.container-image.group=<your-group-name>
quarkus.container-image.name=<you-container-name>
quarkus.jib.base-jvm-image=registry.access.redhat.com/ubi9/openjdk-21-runtime (1)
quarkus.jib.platforms=linux/amd64,linux/arm64 (2)
1 仮想スレッドをサポートするベースイメージを使用するようにしてください。ここでは、Java 21 を提供するイメージを使用します。設定しない場合は、Quarkus によって Java 21+ を提供するイメージが自動的に選択されます。
2 ターゲットアーキテクチャーを選択します。複数選択して multi-archs イメージを構築できます。

次に、通常と同じようにコンテナーをビルドします。 例えば、Maven を使用している場合、次を実行します。

mvn package

仮想スレッドを使用した Quarkus アプリケーションのネイティブ実行可能ファイルへのコンパイル

ローカルにインストールした GraalVM の使用

@RunOnVirtualThread を活用した Quarkus アプリケーションをネイティブ実行可能ファイルにコンパイルするには、仮想スレッドをサポートする GraalVM/Mandrel native-image を使用する必要があり、少なくとも Java 21 を提供する必要があります。

ネイティブコンパイルガイド に示されているように、ネイティブ実行可能ファイルをビルドします。 たとえば、Maven の場合は、以下を実行します。

mvn package -Dnative

コンテナー内ビルドの使用

コンテナー内ビルドでは、コンテナー内で動作する native-image コンパイラを使用して Linux 64 実行可能ファイルをビルドできます。 これは、 native-image をマシンにインストールする手間を省き、必要な GraalVM バージョンを設定することもできます。 コンテナー内ビルドを使用するには、DockerまたはPodmanがマシンにインストールされている必要があることに注意してください。

そして application.properties ファイルに追加します。

# In-container build to get a linux 64 executable
quarkus.native.container-build=true (1)
1 コンテナー内ビルドを有効にします。
ARM/64 から AMD/64 へ

Mac M1 または M2 (ARM64 CPU を使用) を使用している場合、コンテナー内ビルドを使用して取得するネイティブ実行可能ファイルは Linux 実行可能ファイルですが、ホスト (ARM64) アーキテクチャーを使用していることに注意する必要があります。 以下のプロパティーで Docker を使用する際に、エミュレーションを使用して強制的にアーキテクチャーを変更することができます。

quarkus.native.container-runtime-options=--platform=linux/amd64

コンパイル時間がかなり長くなる (10分以上) ことに注意してください。

仮想スレッドを使用したネイティブアプリケーションのコンテナー化

ネイティブ実行可能ファイルにコンパイルされた仮想スレッドを使用して Quarkus アプリケーションを実行するコンテナーをビルドするには、 Linux/AMD64 実行ファイル (ARM マシンを対象としている場合はARM64) を用意する必要があります。

application.propertiesネイティブコンパイルのセクション で説明した設定が含まれているようにしてください。

次に、通常と同じようにコンテナーをビルドします。 例えば、Maven を使用している場合、次を実行します。

mvn package -Dnative
ネイティブコンテナーイメージをビルドしたいときに、すでに既存のネイティブイメージがある場合は、 -Dquarkus.native.reuse-existing=true を設定すれば、ネイティブイメージのビルドは再実行されません。

仮想スレッドで複製されたコンテキストの使用

@RunOnVirtualThread でアノテーションされたメソッドは、複製された元のコンテキストを継承します (詳細は 複製されたコンテキストのリファレンスガイド を参照)。 そのため、フィルタやインターセプタによって複製されたコンテキストに書き込まれたデータ (およびリクエストスコープが複製されたコンテキストに格納されているため、リクエストスコープ) は、メソッドの実行中に (フィルタやインターセプタが仮想スレッド上で実行されていなくても) 利用可能です。

ただし、スレッドローカルは伝播されません。

仮想スレッド名

仮想スレッドは、デフォルトではスレッド名なしで作成されます。これは、デバッグやロギング目的で実行を識別するためには実用的ではありません。 Quarkus の管理対象仮想スレッドには名前が付けられ、 quarkus-virtual-thread- というプレフィックスが付けられます。 このプレフィックスはカスタマイズすることも、空の値を設定して命名を完全に無効にすることもできます。

quarkus.virtual-threads.name-prefix=

仮想スレッドエグゼキュータの注入

仮想スレッド上でタスクを実行するために、Quarkus は内部 ThreadPerTaskExecutor を管理します。 まれにこのエクゼキューターに直接アクセスする必要がある場合は、 @VirtualThreads CDI 修飾子を使用して注入できます。

Virtual Thread ExecutorService の注入は実験的なもので、将来のバージョンで変更される可能性があります。
package org.acme;

import org.acme.fortune.repository.FortuneRepository;

import java.util.concurrent.ExecutorService;

import jakarta.enterprise.event.Observes;
import jakarta.inject.Inject;
import jakarta.transaction.Transactional;

import io.quarkus.logging.Log;
import io.quarkus.runtime.StartupEvent;
import io.quarkus.virtual.threads.VirtualThreads;

public class MyApplication {

    @Inject
    FortuneRepository repository;

    @Inject
    @VirtualThreads
    ExecutorService vThreads;

    void onEvent(@Observes StartupEvent event) {
        vThreads.execute(this::findAll);
    }

    @Transactional
    void findAll() {
        Log.info(repository.findAllBlocking());
    }

}

仮想スレッドアプリケーションのテスト

上述したように、仮想スレッドにはいくつかの制限があり、アプリケーションのパフォーマンスやメモリー使用量に大きな影響を与える可能性があります。 junit5-virtual-threads エクステンションは、テストの実行中にピン留めされたキャリアースレッドを検出する方法を提供します。 このため、最も顕著な制限のひとつを取り除いたり、問題に気づいたりすることができます。

この検出を有効にするには

  • 1) junit5-virtual-threads の依存関係をプロジェクトに追加します。

<dependency>
    <groupId>io.quarkus.junit5</groupId>
    <artifactId>junit5-virtual-threads</artifactId>
    <scope>test</scope>
</dependency>
  • 2) テストケースに、 io.quarkus.test.junit5.virtual.VirtualThreadUnitio.quarkus.test.junit.virtual.ShouldNotPin のアノテーションを追加します:

@QuarkusTest
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
@VirtualThreadUnit // Use the extension
@ShouldNotPin // Detect pinned carrier thread
class TodoResourceTest {
    // ...
}

テストを実行する場合は (Java 21+ を使用することを忘れないでください)、Quarkus はピン留めされたキャリアースレッドを検出します。 この場合、テストは失敗します。

@ShouldNotPin はメソッドに直接使うこともできます。

junit5-virtual-threadsは 、ピニングが避けられない場合のために @ShouldPin アノテーションも提供しています。 次のスニペットは @ShouldPin アノテーションの使い方を示しています。

@VirtualThreadUnit // Use the extension
public class LoomUnitExampleTest {

    CodeUnderTest codeUnderTest = new CodeUnderTest();

    @Test
    @ShouldNotPin
    public void testThatShouldNotPin() {
        // ...
    }

    @Test
    @ShouldPin(atMost = 1)
    public void testThatShouldPinAtMostOnce() {
        codeUnderTest.pin();
    }

}

仮想スレッドメトリクス

アプリケーションに次のアーティファクトを追加することで、Micrometer 仮想スレッド バインダー を有効化できます。

<dependency>
    <groupId>io.micrometer</groupId>
    <artifactId>micrometer-java21</artifactId>
</dependency>

このバインダーは、ピニングイベントの数と、開始またはパーク解除に失敗した仮想スレッドの数を追跡します。 詳細は、 MicroMeter ドキュメント を参照してください。

application.properties で次のプロパティーを設定することで、バインダーを明示的に無効化できます。

# The binder is automatically enabled if the micrometer-java21 dependency is present
quarkus.micrometer.binder.virtual-threads.enabled=false

さらに、アプリケーションが仮想スレッドをサポートしていない JVM (Java 21 より前) 上で実行されている場合、バインダーは自動的に無効化されます。

application.properties で次のプロパティーを設定することで、収集されたメトリクスにタグを関連付けできます。

quarkus.micrometer.binder.virtual-threads.tags=tag_1=value_1, tag_2=value_2

関連コンテンツ