注目記事

【Javaコード入門】スレッド_⑤Executorsクラス

スレッドプールを利用する – 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メソッドであらかじめスレッドを複数用意しておき、再利用する例です。

PoolSample.java
  1. package com.example.mynavi.thread;
  2.  
  3. import java.util.Date;
  4. import java.util.concurrent.ExecutorService;
  5. import java.util.concurrent.Executors;
  6.  
  7. public class PoolSample {
  8.   private static class MyThread implements Runnable {
  9.     @Override
  10.     public void run() {
  11.       System.out.println(new Date());
  12.     }
  13.   }
  14.  
  15.   public static void main(String[] args) {
  16.     var service = Executors.newFixedThreadPool(3);
  17.     service.execute(new MyThread());
  18.     service.execute(new MyThread());
  19.     service.shutdown();
  20.   }
  21. }

  1. Sat Jan 11 16:07:03 JST 2025
  2. Sat Jan 11 16:07:03 JST 2025

スレッドプールからスレッドを取り出すには、ExecutorService#executeメソッドにRunnable実装オブジェクトを渡すだけです。スレッドの生成からプールに戻すまでの流れは、スレッドプールが管理するので意識する必要はありません。shutdownメソッドでスレッドプールを破棄します。

仮想スレッド

従来のJavaスレッドはネイティブスレッド(=OS側が管理するスレッド)と1:1の関係にありました。ネイティブスレッドはJava仮想マシンの外部で生成されるため、大量のスレッド生成に際しては性能が劣化しやすいという問題があります。
そこでJava 21以降では、Java内部で生成される仮想スレッドというしくみが導入されました。仮想スレッドはネイティブスレッドに比べて、生成のオーバーヘッドも小さいというメリットがあります。
仮想スレッドを生成するには、以下のようなコードを書きます(以下は上の例を書き換えたものです)。

  1. var factory = Thread.ofVirtual().factory();
  2. try(var service = Executors.newFixedThreadPool(3, factory)) {

「Thread.ofVirtual().factory()」でスレッドを生成するためのファクトリー(生成オブジェクト)を準備しています。ofVirtualで仮想スレッドを生成する、という意味で、この部分を「ofPlatform()」とすることで、従来のネイティブスレッドを生成することもできます。
  ファクトリーが生成できたら、あとはnewFixedThreadPoolなどのメソッドに引き渡すだけです。

スレッド_目次
Threadクラス/Runnableインターフェイス
synchronized修飾子/ブロック
ReentrantLockクラス
AtomicXxxxxクラス
Executorsクラス

監修

山田祥寛(有限会社 WINGSプロジェクト)
静岡県榛原町生まれ。一橋大学経済学部卒業後、NEC にてシステム企画業務に携わるが、2003年 4 月に念願かなってフリーライターに転身。Microsoft MVP for Visual Studio and Development Technologies。執筆コミュニティ「WINGSプロジェクト(https://wings.msn.to/)」の代表でもある。主な著書に『改訂 3 版JavaScript 本格入門』(技術評論社)、「独習シリーズ(C#・Python・PHP・Ruby・JSP&サーブレットなど)」(翔泳社)、「速習シリーズ(ASP.NET Core・Vue.js・React・TypeScript・ECMAScript、Laravel など)」(Amazon Kindle)など。売り上げの累計は100万部を超える。