Master Java’s ScheduledThreadPoolExecutor: Fixed Rate, Fixed Delay & Leader‑Follower

This article explains Java's ScheduledThreadPoolExecutor, covering its two scheduling modes—fixed‑rate and fixed‑delay—its underlying DelayedWorkQueue implementation, and how it employs the Leader‑Follower pattern to efficiently manage delayed task execution.

Programmer DD
Programmer DD
Programmer DD
Master Java’s ScheduledThreadPoolExecutor: Fixed Rate, Fixed Delay & Leader‑Follower

ScheduledThreadPoolExecutor is a widely used Java tool for timed scheduling, offering two common modes: fixed‑rate execution and fixed‑delay execution, where the delay is measured from the end of the previous execution to the start of the next.

1.scheduleAtFixedRate(Runnable command, long initialDelay, long period, TimeUnit unit)
2.scheduleWithFixedDelay(Runnable command, long initialDelay, long delay, TimeUnit unit)

It extends ThreadPoolExecutor and uses a custom DelayedWorkQueue to meet scheduling needs.

public ScheduledThreadPoolExecutor(int corePoolSize) {
    super(corePoolSize, Integer.MAX_VALUE,
          DEFAULT_KEEPALIVE_MILLIS /*10L*/, MILLISECONDS,
          new DelayedWorkQueue());
}

DelayedWorkQueue is a min‑heap based queue that uses a ReentrantLock for thread‑safety; each ScheduledFutureTask stores a heapIndex to allow O(1) cancellation.

Leader‑Follower Mode

Unlike a regular thread pool, tasks submitted to a scheduled pool are delayed, so worker threads block on queue.take(). To avoid waking all threads when the next task’s delay expires, ScheduledThreadPoolExecutor adopts the Leader‑Follower pattern: one thread becomes the leader, waiting with awaitNanos until the head task’s scheduled time, while other threads remain followers, waiting indefinitely.

public RunnableScheduledFuture<?> take() throws InterruptedException {
    final ReentrantLock lock = this.lock;
    lock.lockInterruptibly();
    try {
        for (;;) {
            RunnableScheduledFuture<?> first = queue[0];
            if (first == null)
                available.await();
            else {
                long delay = first.getDelay(NANOSECONDS);
                if (delay <= 0L)
                    return finishPoll(first);
                first = null;
                if (leader != null)
                    available.await();
                else {
                    Thread thisThread = Thread.currentThread();
                    leader = thisThread;
                    try {
                        available.awaitNanos(delay);
                    } finally {
                        if (leader == thisThread)
                            leader = null;
                    }
                }
            }
        }
    } finally {
        if (leader == null && queue[0] != null)
            available.signal();
        lock.unlock();
    }
}

When a new element becomes the heap head, offer() clears the current leader and signals a waiting thread so that the leader‑follower cycle can continue.

public boolean offer(Runnable x) {
    final ReentrantLock lock = this.lock;
    lock.lock();
    try {
        // insert into queue
        if (queue[0] == e) {
            leader = null;
            available.signal();
        }
    } finally {
        lock.unlock();
    }
    return true;
}
Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

JavaconcurrencySchedulingScheduledThreadPoolExecutorleader-follower
Programmer DD
Written by

Programmer DD

A tinkering programmer and author of "Spring Cloud Microservices in Action"

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.