Javaは仮想スレッディングのプレビューバージョンを導入し、アプリケーションスループットを大幅に改善します

OpenJDKのJEP425:仮想スレッド(プレビュー)機能の提案によると:Javaプラットフォームは仮想スレッドを導入します。仮想スレッドは軽量スレッドであり、高スループットの並行アプリケーションの作成、保守、および監視のワークロードを大幅に削減できます。

Java開発者は、並行サーバーアプリケーションの構成要素として常にスレッドに依存してきました。各メソッドのステートメントはスレッド内で実行され、各スレッドは、ローカル変数を格納し、メソッド呼び出しを調整するためのスタックを提供します。エラー。スレッドは、Javaの並行性の単位であり、Javaツールのコア基盤です。デバッガーはスレッドのメソッドのステートメントをステップスルーし、プロファイラーは複数のスレッドの動作を視覚化します。

現在、JDKはプラットフォームスレッドをオペレーティングシステム(OS)スレッドのラッパーとして実装しており、JDKの各インスタンスはプラットフォームスレッドであり、プラットフォームスレッドは基盤となるOSスレッド上でJavaコードを実行し、コードのライフサイクル全体にわたって実行されます。 OSスレッドをキャプチャします。プラットフォームスレッドの数はOSスレッドの数によって制限され、OSスレッドは高価であり、あまり多くを占めることはできません。その結果、現在のJDKのスレッド化へのアプローチは、アプリケーションのスループットをハードウェアがサポートするスループットよりもはるかに低く制限しています。

仮想スレッドについて

仮想スレッドjava.lang.Threadは、基盤となるオペレーティングシステムスレッド(OSスレッド)でJavaコードを実行するスレッドですが、コードの存続期間中はOSスレッドのインスタンスをキャプチャしません。これは、多くの仮想スレッドが同じOSスレッドでJavaコードを実行し、それを効果的に共有できることを意味します。

仮想スレッドは、オペレーティングシステムではなく、JDKによって提供されるスレッドの軽量実装であり、ユーザーモードスレッドの形式です。ユーザーモードスレッドは、オペレーティングシステムスレッドの概念が成熟しておらず、十分に普及しておらず、JavaのすべてのグリーンスレッドがOSスレッド(M:1スケジューリング)をスレッドと共有していたときに、 Javaの初期バージョンでは「グリーンスレッド」と呼ばれていました。コンセプトの開発により、グリーンスレッドは最終的に現在のプラットフォームスレッドに追い抜かれ、OSスレッドのラッパーとして実装されました(1:1スケジューリング)が、新しく導入された仮想スレッドはM:Nスケジューリングを採用しています。 (M)個の仮想スレッドは、少数(N)個のOSスレッドで実行されるようにスケジュールされます。

より高いスループット

開発者は仮想スレッドまたはプラットフォームスレッドの使用を選択できますが、仮想スレッドは高スループットのサーバーアプリケーションでより優れたパフォーマンスを発揮します。たとえば、1秒間スリープする次のコードは、多数の仮想スレッドを作成します。プログラムは、最初に ExecutorServiceを取得します。これにより、送信されたタスクごとに新しい仮想スレッドが作成され、次に10,000個のタスクが送信され、すべてのタスクが完了するのを待ちます。

try (var executor = Executors.newVirtualThreadPerTaskExecutor()) {
    IntStream.range(0, 10_000).forEach(i -> {
        executor.submit(() -> {
            Thread.sleep(Duration.ofSeconds(1));
            return i;
        });
    });
}  // executor.close() is called implicitly, and waits

最新のハードウェアは、このようなコードを同時に実行する10,000の仮想スレッドを簡単にサポートできます。プログラムがタスクごとに新しいプラットフォームスレッドを作成するExecutorService(Executors.newCachedThreadPool()など)を使用する場合、10,000プラットフォームスレッドを作成しようとします。これは10,000 OSスレッドを意味し、プログラムはほとんどの操作で機能しません。クラッシュします。または、プログラムは、Executors.newFixedThreadPool(200)などのプラットフォームスレッドをプールから取得するExecutorServiceを使用しますが、これはそれほど優れていません。ExecutorServiceは、これらの10,000個のタスクを共有するために200個のプラットフォームスレッドを作成し、タスクは同時にではなく順次実行され、プログラムの完了には長い時間がかかります。

上記のプログラムの場合、200のプラットフォームスレッドを持つプールは1秒あたり200タスクのスループットしか達成できませんが、仮想スレッドは1秒あたり約10,000タスクのスループットを達成できます(十分なウォームアップ後)。また、サンプルプログラムで10000から1,000,000に変更すると、プログラムは1,000,000タスクを送信し、同時に実行される1,000,000仮想スレッドを作成し、(十分なウォームアップ後)約1,000,000タスク/秒のスループットを達成します。

要約すると、仮想スレッドはより高速なスレッドではありません。プラットフォームスレッドよりも高速にコードを実行することはありません。これらは、速度(待ち時間の短縮)ではなく、規模(スループットの向上)を提供するために存在します。

仮想スレッドを有効にする方法は?

仮想スレッドは現在、他のマルチスレッド言語(GoのゴルーチンやErlangのプロセスなど、C ++の安定した機能)で広く使用されていますが、JavaのプレビューAPIであり、デフォルトで無効になっています。JDK XXでこの機能を試すには、プレビューAPIを次の方法で有効にする必要があります。

  • プログラムをjavac--releaseXX --enable-preview Main.javaでコンパイルし、java--enable-previewMainで実行します。
  • ソースコードランチャーを使用する場合は、java --release XX--enable-previewMain.javaを使用してプログラムを実行します。
  • jshellを使用する場合は、jshell--enable-previewから始めてください

仮想スレッドの詳細については、OpenJDKの JDK Issue-8277131を参照してください 。この提案は2021/11/15に作成され、現在JEPプロセスの最初のフェーズにあり、安定したリリースまでにはしばらく時間がかかります。

おすすめ

転載: www.oschina.net/news/190175/java-virtual-threads-preview