見出し画像

Java21で正式リリースされた Virtual Threads に触れる


はじめまして!ウイングアーク1stのとむです。
普段の業務ではJavaでWebアプリケーションの開発をしています。
初めての記事投稿ということで、最近Javaに正式追加された Virtual Threads について書きたいと思います。

Virtual Threads とは

Project Loom として開発された、高スループットを実現できる軽量なスレッドの実装です。
詳しい背景などは JEP 444 などで確認できます。

Virtual Threads が必要になった経緯

従来のJavaのスレッドはOSのネイティブスレッドと1対1で対応しています。
スレッド数分のメモリ消費に加えて、スレッドの生成やコンテキストスイッチにかかるコストも増えていきます。
そのため、通常は無尽蔵にスレッドを生成するような設計にはせず、スレッドプールなどを用いてスレッド数を制限することが多いと思います。

例えば、1リクエストに対して1スレッドを割り当てるサーバーアプリケーションを考えた時、最大スレッド数を超えるリクエストに対して待ちが発生することになります。
I/Oの完了を待機をするだけでもスレッドをブロックしてしまい、CPUの使用率は低いのに処理量が少ないということにも繋がります。

こういった問題を解決するためにノンブロッキングI/Oを利用することができましたが、プログラミングスタイルが大きく異なるという課題がありました。
新しく導入された Virtual Threads では、多数の仮想スレッドを少数のネイティブスレッドにマッピングし、従来のスレッドを扱うスタイルのままノンブロッキングI/Oの恩恵を受けることができます。

Virtual Threads のメリット

  • スケーラビリティ:仮想スレッドは非常に軽量であるため、数百万単位のスレッドを作成することができます。

  • プログラミングの容易さ:従来の同期スタイルのプログラムに慣れ親しんだ開発者が、非同期プログラミングの複雑さを避けつつ、並行処理を実現することができます。

  • 資源の効率性:仮想スレッドは少数のネイティブスレッドにマッピングされるため、システム資源を効率的に利用できます。

Virtual Threads を使ってみる

新しいAPIがいくつか追加されていますが、基本的な使い方は従来のThreadと同じです。
従来のスレッドのことは Platform thread と呼ぶことで区別されています。

Executorを使うことで高レベルなAPIでスレッドの管理をすることもできます。
以下の例では仮想スレッドを1,000,000個作成していますが、問題なく動作します。

使い所の考察

従来の慣れ親しんだThreadの使い方のまま、ブロッキングI/O処理のスループットの向上を狙えるところに価値があります。
真っ先に思いつくのはthread-per-requestスタイルで記述されたサーバー処理です。
Webアプリケーションやマイクロサービスで大量のリクエストを処理するようなシステムであれば、仮想スレッドを利用することでスループットを大幅に向上させることができる可能性があります。
Webアプリケーションフレームワークを利用している場合は、フレームワーク側の対応を待つことになると思われます。

注意点

従来のスレッドスタイルの場合、スレッドをプールすることがありますが、これには『同時処理数を制限できる』という副次的な効果がありました。
単純に仮想スレッドに置き換えてしまうことで、負荷を掛けてはいけないところに掛かってしまう可能性があります。
仮想スレッドでもそういった事を実現したい時にはSemaphoreクラスを使うことができます。

まとめ

Java 21で導入された仮想スレッドは、従来のプログラミングスタイルのまま従来のスレッドモデルの問題を解決します。
特にI/O待ちによるスレッドブロッキングの課題を解消することで、アプリケーションのパフォーマンスを向上させることができる可能性があります。
自分たちの製品の開発にも活用できないか考えていきたいです。
また、機会があれば動作原理についても掘り下げていきたいと思います。

参考文献


この記事が気に入ったらサポートをしてみませんか?