Scheduled and periodic tasks

Multithreading · lesson 21 of 38 · 3 min read

Run work later or on a repeat with ScheduledExecutorService, and pick the repeat mode you actually want.

Open this lesson in the learning hub

Key points

  • schedule runs a task once after a delay. It accepts a Callable, so it can hand a value back.
  • scheduleAtFixedRate measures the period from each start, so a slow run makes the next one start immediately.
  • scheduleWithFixedDelay measures from each finish, so the gap between runs is always the same.
  • An exception from a periodic task silently cancels the whole schedule. Wrap the body in try/catch and log it.
  • The returned ScheduledFuture is the off switch. cancel(false) lets the run in progress finish.
  • The old Timer has one thread and dies on the first uncaught exception. Use a scheduled executor instead.

Example

import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;

public class Main {
    public static void main(String[] args) throws Exception {
        ScheduledExecutorService sched = Executors.newScheduledThreadPool(2);
        AtomicInteger ticks = new AtomicInteger();

        ScheduledFuture<?> rate = sched.scheduleAtFixedRate(
                () -> System.out.println("fixed-rate tick " + ticks.incrementAndGet()),
                50, 100, TimeUnit.MILLISECONDS);          // period counted from each start

        sched.schedule(() -> System.out.println("one-shot fired at 120 ms"), 120, TimeUnit.MILLISECONDS);

        ScheduledFuture<String> value = sched.schedule(() -> "delayed result", 150, TimeUnit.MILLISECONDS);
        System.out.println("schedule() gave : " + value.get());

        Thread.sleep(200);
        rate.cancel(false);                               // periodic tasks run until cancelled
        System.out.println("ticks fired     : " + ticks.get());

        sched.shutdown();
        sched.awaitTermination(2, TimeUnit.SECONDS);
        System.out.println("scheduler done  : " + sched.isTerminated());
    }
}

fixedRate keeps a rhythm. fixedDelay keeps a gap.

This is a reading copy. The full lesson — with the visual explainer, the interactive lab and a Run button for the code — lives in the Multithreading course, and every lesson in it is listed on the Multithreading contents page.