Javaの新しいVirtual Threadを試してみた
目次
こんにちは、システムエンジニアのキュウです。去年、Java19のリリースに伴い、新機能のVirtual Threadがプレビュー状態になりました。いよいよ開発者が利用できるようになります。自分もこの機会に新しい「Thread」を試して、従来のJVM Threadとの違いを確認してみました。
Virtual Threadとは
Virtual Threadは、OpenJDKでのプロジェクトLoomの成果物です。Javaプラットフォームにも使いやすい軽量なThreadの実装を提供することを目標としています。
Virtual Threadと従来のJVM Threadとの違い
JVM Threadを使用する場合、次のコードが必要です。
1 |
new Thread(() -> System.out.println("jvm thread...")).start(); |
Virtual Threadを使用する場合、次のコードとなります。
1 |
Thread.startVirtualThread(() -> System.out.println("virtual thread...")).start(); |
非常によく似ていますが、関数名が少し変更されたぐらいでしょうか?
実は、JVM ThreadとOS Threadの間には下記図のように1対1の関係があります。
JVM Threadの作成と破棄は、大量のシステムリソースを消費します。 多数のThreadでリクエストを処理するのは負荷の高い操作だと思われます。
Virtual Threadの方は下図のようにJVM ThreadとM対Nの関係に変わります。
JVM Threadよりも軽く実装されており、作成と破棄に消費するリソースがはるかに少なくなりそうです。その上、Virtual ThreadのスケジューリングはJavaプラットフォームによって制御されます。「Thread」は軽量になって使用するのに重くなりません。
高負荷の利用場面でも、Virtual Threadの導入により、Thread間の競合によって引き起こされるデッドロックや競合状態などの問題を回避でき、信頼性も向上するため、実際のパフォーマンスについてすごく楽しみです。
試してみる
Red Hatの記事では「Virtual ThreadのスケジューリングはJavaプラットフォームに渡される」とあるため、ここでSocket Serverを作って、Virtual ThreadとプーリングしたJVM Thread二つの方式で大量のリクエストを処理してみてパフォーマンスに大きな違いはあるか試してみます。
1 2 3 |
Client:window 11 laptop, JMeter Server:2C2G Rocky Linux 9 VM on NAS Server JDK:GraalVM CE 22.3.1 |
テストコード
まず、リクエストを処理するためのThreadプールを作成します。
JVM Threadを使用する場合:
1 |
ExecutorService service = Executors.newFixedThreadPool(100); |
Virtual Threadを使用する場合:
1 |
ExecutorService service = Executors.newVirtualThreadPerTaskExecutor(); |
クライアントからのリクエストをハンドラに渡す。
1 2 3 4 5 6 7 |
try (ServerSocket ss = new ServerSocket(8000)) { while (true) { service.submit(new EchoHandler(ss.accept())); } } catch (IOException e) { e.printStackTrace(); } |
ハンドラの中に受信したメッセージをEchoする。
1 2 3 4 5 6 7 |
try { byte[] input = new byte[1024 * 10]; String msg = process(input, socket.getInputStream().read(input)); socket.getOutputStream().write(String.format("ECHO: %s", msg).getBytes()); } catch (IOException ex) { ex.printStackTrace(); } |
試験結果
上図のように、2コアCPUの仮想サーバで同時リクエストが1000を超える場合のみ、Virtual ThreadはJVM Threadよりも優れた処理パフォーマンスを示しています。
最後に
自分の低スペックの仮想サーバではパフォーマンスに大きな差が見られなかったのは残念ですが、Virtual Threadの主戦場はハイスペックなサーバ上だと思われます。開発者の観点から見ると、Javaプラットフォームの進化に伴い、「Thread」を使用するコストはますます低くなり、頻繁の切り替えによるパフォーマンスの低下はまったく考慮しなくてもよくなります。将来「Thread」を自由に作成して使用できることを非常に期待しています。