Java Academy · レッスン

定期タスクのための ScheduledExecutorService

ポーリングやバックグラウンド保守処理のために、固定レートまたは固定遅延でタスクをスケジュールします。

レッスン 4/413 ステップ

「定期タスクのための ScheduledExecutorService」はCoddyKit上の無料Java Academyレッスンです。 これはレッスン4/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはJava Academy学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 Java Academyコースには全4レッスンが含まれています。

ScheduledExecutorServiceを使う理由

ScheduledExecutorServiceはExecutorServiceを拡張し、タスクのスケジュール実行をサポートします。従来のTimer/TimerTaskクラスに代わるもので、スレッドプールを基盤とし、例外に安全に対処できるスケジューラーです。

import java.util.concurrent.*;

ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(2);

// One-shot delay
scheduler.schedule(
    () -> System.out.println("Runs once after 3 seconds"),
    3, TimeUnit.SECONDS
);

// Don't forget to shut down eventually:
// scheduler.shutdown();

schedule:1回限りの遅延実行

schedule(task, delay, unit)は、指定した遅延時間の後にタスクを1回実行します。RunnableとCallableの両方で使用できます。

ScheduledExecutorService s = Executors.newScheduledThreadPool(1);

// Runnable:
ScheduledFuture<?> sf1 = s.schedule(
    () -> System.out.println("Runnable fired!"), 2, TimeUnit.SECONDS);

// Callable:
ScheduledFuture<Integer> sf2 = s.schedule(
    () -> { System.out.println("Callable fired!"); return 42; },
    2, TimeUnit.SECONDS);

System.out.println(sf2.get()); // 42 (after 2 seconds)

scheduleAtFixedRate

scheduleAtFixedRate(task, initialDelay, period, unit)は、一定の割合でタスクを繰り返し実行します。タスクの実行時間が期間より長い場合、次の実行は前のタスクの完了直後に開始されます(重複実行はありません)。

ScheduledExecutorService s = Executors.newScheduledThreadPool(1);
AtomicInteger count = new AtomicInteger();

ScheduledFuture<?> sf = s.scheduleAtFixedRate(
    () -> System.out.println("Tick " + count.incrementAndGet()),
    0,   // initial delay
    1,   // period
    TimeUnit.SECONDS
);

Thread.sleep(5000);
sf.cancel(false); // stop after 5 ticks
s.shutdown();

scheduleWithFixedDelay

scheduleWithFixedDelay(task, initialDelay, delay, unit)は、各タスクの完了後に指定した遅延時間を待ってから、次のタスクを開始します。タスクの実行時間が変動するポーリングに適しています。

s.scheduleWithFixedDelay(
    () -> {
        System.out.println("Polling... " + Instant.now());
        // variable-length polling task
    },
    0,  // no initial delay
    5,  // 5-second gap AFTER each completion
    TimeUnit.SECONDS
);
// Next execution = task end + 5 seconds (not task start)

固定レートと固定遅延の違い

重要な違い:

  • scheduleAtFixedRate:次の開始時刻 = 前回の開始時刻 + 期間(ずれのないタイミング)
  • scheduleWithFixedDelay:次の開始時刻 = 前回の終了時刻 + 遅延時間(実行間に必ず間隔が空く)

ハートビートにはfixedRateを使用し、タスクの実行時間が変動するポーリングにはfixedDelayを使用します。

ScheduledFuture:キャンセル

schedule/scheduleAtFixedRate/scheduleWithFixedDelayはScheduledFutureを返します。実行中のタスクには割り込みを送信せず、今後の実行を停止するにはcancel(false)を呼び出します。

ScheduledFuture<?> sf = scheduler.scheduleAtFixedRate(
    () -> System.out.println("Heartbeat"), 0, 1, TimeUnit.SECONDS);

// Cancel after 5 seconds
scheduler.schedule(() -> sf.cancel(false), 5, TimeUnit.SECONDS);

スケジュールタスクの例外処理

スケジュールされたタスクが未捕捉例外をスローすると、スケジューラーは繰り返し実行を通知なしに停止します。以降の実行は行われません。必ずtry-catchでラップしてください。

scheduler.scheduleAtFixedRate(() -> {
    try {
        // risky work
        if (Math.random() < 0.3) throw new RuntimeException("transient");
        System.out.println("Success");
    } catch (Exception e) {
        System.err.println("Task error: " + e.getMessage());
        // task continues to run on next interval
    }
}, 0, 2, TimeUnit.SECONDS);

実践例:キャッシュの更新

スケジュールタスクを使用して、キャッシュを定期的に更新します。

class PriceCache {
    private volatile Map<String, Double> prices = new HashMap<>();
    
    PriceCache(ScheduledExecutorService scheduler) {
        scheduler.scheduleAtFixedRate(this::refresh, 0, 30, TimeUnit.SECONDS);
    }
    
    private void refresh() {
        System.out.println("Refreshing prices...");
        // prices = fetchFromDatabase();
    }
    
    Double getPrice(String symbol) { return prices.get(symbol); }
}

実践例:バックオフ付きリトライ

スケジュールされたタスクを使用して、指数バックオフによる再試行を実装します:

void retryWithBackoff(Runnable task, int maxRetries, ScheduledExecutorService s) {
    AtomicInteger attempts = new AtomicInteger(0);
    long[] delay = {1}; // seconds
    
    Runnable wrapper = new Runnable() {
        public void run() {
            try {
                task.run();
            } catch (Exception e) {
                int n = attempts.incrementAndGet();
                if (n < maxRetries) {
                    delay[0] *= 2;
                    s.schedule(this, delay[0], TimeUnit.SECONDS);
                } else System.err.println("Max retries reached");
            }
        }
    };
    s.execute(wrapper);
}

監視: getDelay と getQueue

スケジューラの状態を確認します:

ScheduledFuture<?> sf = scheduler.schedule(() -> {}, 10, TimeUnit.SECONDS);
System.out.println("Delay remaining: " + sf.getDelay(TimeUnit.SECONDS) + "s");

// ThreadPoolExecutor provides queue inspection:
if (scheduler instanceof ScheduledThreadPoolExecutor ste) {
    System.out.println("Queue size: " + ste.getQueue().size());
}

シャットダウンとタスクの消化

シャットダウン時に、スケジュールされたタスクを引き続き実行するかどうかを決定します:

ScheduledThreadPoolExecutor ste = (ScheduledThreadPoolExecutor)
    Executors.newScheduledThreadPool(2);

// Cancel scheduled tasks on shutdown (default: false = they run)
ste.setExecuteExistingDelayedTasksAfterShutdownPolicy(false);
ste.setContinueExistingPeriodicTasksAfterShutdownPolicy(false);

ste.shutdown();

クイックチェック

scheduleAtFixedRate(..., 1, TimeUnit.SECONDS)でスケジュールされたタスクの完了に3秒かかる場合、スケジューラはどのように処理しますか?

まとめ: ScheduledExecutorService

重要なポイント:

  • schedule() — 遅延後に1回だけ実行
  • scheduleAtFixedRate() — ずれのないタイミング(開始から開始まで)
  • scheduleWithFixedDelay() — 保証された間隔(完了から開始まで)
  • キャッチされない例外が発生すると、繰り返しタスクは暗黙的に停止します — 必ずtry-catchで囲んでください
  • ScheduledFuture.cancel(false)でキャンセル
無料で開始

AI チューターと学ぶ Java — 無料

ブラウザでリアルコードを書いて実行し、24/7 の AI チューターから瞬時にサポートを受け、ウェブまたはアプリで続きから学習できます。

コース
104
レッスン
374

よくある質問

「定期タスクのための ScheduledExecutorService」レッスンは無料ですか?

はい。「定期タスクのための ScheduledExecutorService」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、Java Academyコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 Java Academyコースには全4レッスンが含まれています。

「定期タスクのための ScheduledExecutorService」で何を学びますか?

ポーリングやバックグラウンド保守処理のために、固定レートまたは固定遅延でタスクをスケジュールします。 ブラウザで直接実行するハンズオンコードでJava Academyを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。

Java Academyを始めるのに経験は必要ですか?

事前経験は必要ありません。CoddyKitのJava Academyは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン4/4です。

「定期タスクのための ScheduledExecutorService」レッスンにはどのくらい時間がかかりますか?

ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。

このJava Academyレッスンでコードを書いて実行できますか?

はい。すべてのJava Academyレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。

このコースのすべてのレッスン

  1. ExecutorService とスレッドプールの種類
  2. タスクの送信:Runnable と Callable
  3. Future とエラー処理
  4. 定期タスクのための ScheduledExecutorService
← Java Academyに戻る