😺

Java Gold ScheduledExecutorServiceのまとめ

2024/11/24に公開

1. ScheduledExecutorService の特徴

ScheduledExecutor=スケジュールドエグゼキュータ

遅延実行: タスクを指定した遅延時間の後に1回だけ実行できます。
定期実行: タスクを一定の間隔で繰り返し実行することができます。
スレッドプールの管理: 複数のスレッドでタスクを管理し、スレッドの使い回しによるリソースの効率化を実現します。
これにより、タイマーのような動作が必要な場合や、特定の時間ごとに実行したい処理を簡単に実装できます。

2. ScheduledExecutorService の作成方法

ScheduledExecutorService インタフェースのインスタンスは、Executors クラスを使って作成できます。

import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;

public class Main {
    public static void main(String[] args) {
        // スレッドプールに2つのスレッドを持つ ScheduledExecutorService を作成
        ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(2);
    }
}

ここで、newScheduledThreadPool(int corePoolSize) メソッドを使用して、指定した数のスレッドを持つ ScheduledExecutorService インスタンスを作成します。

3. 主なメソッド

schedule(Runnable command, long delay, TimeUnit unit)

用途: 指定した遅延時間後に1回だけタスクを実行する。

command : 実行するタスク(Runnable または Callable)。
delay : タスク実行までの遅延時間。
unit : 時間の単位(TimeUnit.SECONDS など)。

scheduler.schedule(() -> System.out.println("Task executed after delay"), 3, TimeUnit.SECONDS);

この例では、3秒後に「Task executed after delay」と表示されます。

scheduleAtFixedRate(Runnable command, long initialDelay, long period, TimeUnit unit)

用途: 初回実行の遅延時間と、以降の実行間隔を指定して、定期的にタスクを実行する。

command : 実行するタスク。
initialDelay: 初回実行までの遅延時間。
period: 次の実行までの間隔。
unit: 時間の単位。

scheduler.scheduleAtFixedRate(() -> System.out.println("Fixed rate task"), 2, 5, TimeUnit.SECONDS);

この例では、最初に2秒後に実行され、その後5秒ごとに「Fixed rate task」と表示されます。

scheduleWithFixedDelay(Runnable command, long initialDelay, long delay, TimeUnit unit)
用途: 初回実行の遅延時間と、前のタスクの終了から次のタスクの開始までの遅延時間を指定して、定期的にタスクを実行する。

command : 実行するタスク。
initialDelay : 初回実行までの遅延時間。
delay : 前のタスクの終了から次のタスクの開始までの遅延時間。
unit : 時間の単位。

scheduler.scheduleWithFixedDelay(() -> System.out.println("Fixed delay task"), 1, 3, TimeUnit.SECONDS);

この例では、最初に1秒後に実行され、前のタスクの終了から3秒後に次のタスクが実行されます。

4. scheduleAtFixedRate と scheduleWithFixedDelay の違い

scheduleAtFixedRate:

タスクの開始時間が一定間隔で実行されます。
例:毎朝9時にタスクを開始するなど、タスク実行開始のタイミングを正確に管理したい場合に適しています。

scheduleWithFixedDelay:

タスクの終了から次の開始までの間隔が一定です。
例:タスクの実行にかかる時間が変動する場合に適しており、タスクの完了後、一定時間待ってから次を実行するパターンで使われます。

5. スレッドプールのシャットダウン

タスクの実行がすべて完了した後は、shutdown() または shutdownNow() メソッドを使ってスレッドプールを停止する必要があります。

shutdown(): 新しいタスクの受付を停止し、既存のタスクが完了するまで待ちます。
shutdownNow(): 現在のタスクを強制終了し、即座に停止します。

scheduler.shutdown();  // 新しいタスクの受付を停止し、既存タスクを完了させる

6. 使用例

以下に、ScheduledExecutorService を使用して定期的にタスクを実行する例

import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

public class ScheduledExecutorExample {
    public static void main(String[] args) {
        ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);

        // 2秒後に1回だけ実行
        scheduler.schedule(() -> System.out.println("One-time delayed task"), 2, TimeUnit.SECONDS);

        // 初回5秒後に開始し、以降10秒ごとに実行
        scheduler.scheduleAtFixedRate(() -> System.out.println("Fixed rate task"), 5, 10, TimeUnit.SECONDS);

        // 初回3秒後に開始し、前回終了から5秒後に実行
        scheduler.scheduleWithFixedDelay(() -> System.out.println("Fixed delay task"), 3, 5, TimeUnit.SECONDS);

        // 実行例のために、30秒後にシャットダウン
        scheduler.schedule(() -> {
            scheduler.shutdown();
            System.out.println("Scheduler shutdown");
        }, 30, TimeUnit.SECONDS);
    }
}

実行結果のイメージ
最初に、2秒後に「One-time delayed task」が一度だけ実行されます。
5秒後に「Fixed rate task」が初めて実行され、その後10秒間隔で繰り返し実行されます。
3秒後に「Fixed delay task」が初めて実行され、その後前回の終了から5秒後に実行されます。
30秒後にスレッドプールがシャットダウンされます。

スレッド作成・実行
Thread クラス - start() でスレッド開始、run() に実行処理を書く
Runnable インターフェース - スレッドで実行する処理をクラスで定義し、Thread クラスに渡す
同期化・通信
synchronized - 排他制御を実現。メソッドやブロックに指定
wait() / notify() / notifyAll() - スレッドの一時停止・再開を制御
スレッドプール
ExecutorService - スレッドプールでタスクを管理 (submit() でタスク追加、shutdown() で終了)
ScheduledExecutorService - タスクをスケジュール実行 (scheduleAtFixedRate() で定期実行)
スレッド間の待機・同期処理
CountDownLatch - 指定した数のスレッドが終了するまで待機 (countDown() でカウントダウン)
CyclicBarrier - 複数スレッドが全員集まるまで待機、一斉に次の処理に進む
マルチスレッド対応コレクション
ConcurrentHashMap - スレッドセーフなハッシュマップ
CopyOnWriteArrayList - 読み取りが多く書き込みが少ない場面で使うスレッドセーフなリスト

まとめ

ScheduledExecutorService は遅延実行や定期実行に適したインタフェースです。
主に schedule、scheduleAtFixedRate、scheduleWithFixedDelay メソッドを使用して、タスクのスケジューリングを行います。
スレッドプールのリソースを確実に解放するために、使用後は shutdown() メソッドで停止させることが推奨されます。
これにより、定期的なバックグラウンドタスクや一時的な遅延実行タスクを効率的に管理できます。

Discussion