スレッドプールを利用する – Executorsクラス
public static ExecutorService newFixedThreadPool(
[int t [,ThreadFactory factory]])
public static ExecutorService newSingleThreadExecutor
([ThreadFactory factory])
static ExecutorService newThreadPerTaskExecutor(ThreadFactory threadFactory)
static ExecutorService newVirtualThreadPerTaskExecutor()static ScheduledExecutorService
newSingleThreadScheduledExecutor(
[ThreadFactory factory])
static ScheduledExecutorService
newScheduledThreadPool(
int size [,ThreadFactory factory])
t:スレッド数
size:待機中でもプールに維持されるスレッド数
factory:スレッド生成に利用するファクトリー
スレッドプールとは、スレッドをあらかじめいくつか用意しておき、再利用するしくみです。スレッドプールを利用することで、必要になる都度、スレッドを生成する必要がなくなりますので、パフォーマンスの改善が期待できます。
スレッドプールを利用するには、Executorsクラス(java.util.concurrentパッケージ)を利用します。Executorsクラスには、スレッドプールを生成するための以下のようなメソッドが用意されています。
| Executorsクラスの主なメソッド | |
|---|---|
| メソッド | 概要 |
| newFixedThreadPool | 指定数のスレッドを確保 |
| newSingleThreadExecutor | 単一のスレッドを確保 |
| newThreadPerTaskExecutor | タスクごとにスレッドを生成 |
| newVirtualThreadPerTaskExecutor | タスクごとに仮想スレッドを生成 |
| newSingleThreadScheduledExecutor | 指定期間おきに実行するスレッド(単一スレッド) |
| newScheduledThreadPool | 指定時間おきに実行するスレッド |
たとえば以下は、newFixedThreadPoolメソッドであらかじめスレッドを複数用意しておき、再利用する例です。
- package com.example.mynavi.thread;
- import java.util.Date;
- import java.util.concurrent.ExecutorService;
- import java.util.concurrent.Executors;
- public class PoolSample {
- private static class MyThread implements Runnable {
- @Override
- public void run() {
- System.out.println(new Date());
- }
- }
- public static void main(String[] args) {
- var service = Executors.newFixedThreadPool(3);
- service.execute(new MyThread());
- service.execute(new MyThread());
- service.shutdown();
- }
- }
↓
- Sat Jan 11 16:07:03 JST 2025
- Sat Jan 11 16:07:03 JST 2025
スレッドプールからスレッドを取り出すには、ExecutorService#executeメソッドにRunnable実装オブジェクトを渡すだけです。スレッドの生成からプールに戻すまでの流れは、スレッドプールが管理するので意識する必要はありません。shutdownメソッドでスレッドプールを破棄します。
仮想スレッド
従来のJavaスレッドはネイティブスレッド(=OS側が管理するスレッド)と1:1の関係にありました。ネイティブスレッドはJava仮想マシンの外部で生成されるため、大量のスレッド生成に際しては性能が劣化しやすいという問題があります。
そこでJava 21以降では、Java内部で生成される仮想スレッドというしくみが導入されました。仮想スレッドはネイティブスレッドに比べて、生成のオーバーヘッドも小さいというメリットがあります。
仮想スレッドを生成するには、以下のようなコードを書きます(以下は上の例を書き換えたものです)。
- var factory = Thread.ofVirtual().factory();
- try(var service = Executors.newFixedThreadPool(3, factory)) {
「Thread.ofVirtual().factory()」でスレッドを生成するためのファクトリー(生成オブジェクト)を準備しています。ofVirtualで仮想スレッドを生成する、という意味で、この部分を「ofPlatform()」とすることで、従来のネイティブスレッドを生成することもできます。
ファクトリーが生成できたら、あとはnewFixedThreadPoolなどのメソッドに引き渡すだけです。
- スレッド_目次
- Threadクラス/Runnableインターフェイス
- synchronized修飾子/ブロック
- ReentrantLockクラス
- AtomicXxxxxクラス
- Executorsクラス
監修