Problem Statement (Asked By Apple)
Design a job scheduler that accepts a function f
and an integer n
. The scheduler should execute the function f
after a delay of n
milliseconds.
Problem link: https://leetcode.com/problems/task-scheduler/description/
Disclaimer: Try solving the problem on your own first! Use this solution only as a reference to learn and improve.
We can implement a job scheduler in various ways, so it’s fine if your approach differs. Here, we’ll demonstrate one possible solution.
A straightforward way is to start a new thread for each delayed function. The thread will sleep for the specified time and then execute the function. This could look something like this:
import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; public class Scheduler { public void delay(Runnable task, int delayInMillis) { new Thread(() -> { try { Thread.sleep(delayInMillis); task.run(); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } }).start(); } public static void main(String[] args) { Scheduler scheduler = new Scheduler(); scheduler.delay(() -> System.out.println("Task executed!"), 1000); } }
While functional, this approach has a significant flaw: each call to delay
creates a new thread, which could lead to excessive thread creation and resource exhaustion.
Instead of creating a new thread for each task, we can use a single dedicated thread to manage all scheduled tasks. We’ll store the tasks in a list along with their scheduled execution times. The thread will periodically check the list for due tasks, execute them, and remove them.
import java.util.ArrayList; import java.util.List; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; public class Scheduler { private final List<Task> tasks = new ArrayList<>(); private final ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor(); public Scheduler() { executor.scheduleAtFixedRate(this::poll, 0, 10, TimeUnit.MILLISECONDS); } private synchronized void poll() { long currentTime = System.currentTimeMillis(); List<Task> toRemove = new ArrayList<>(); for (Task task : tasks) { if (task.dueTime <= currentTime) { task.runnable.run(); toRemove.add(task); } } tasks.removeAll(toRemove); } public synchronized void delay(Runnable task, int delayInMillis) { tasks.add(new Task(task, System.currentTimeMillis() + delayInMillis)); } private static class Task { Runnable runnable; long dueTime; Task(Runnable runnable, long dueTime) { this.runnable = runnable; this.dueTime = dueTime; } } public static void main(String[] args) throws InterruptedException { Scheduler scheduler = new Scheduler(); scheduler.delay(() -> System.out.println("Task 1 executed!"), 1000); scheduler.delay(() -> System.out.println("Task 2 executed!"), 2000); } }
Task
object, which contains the function (Runnable
) and the scheduled execution time (dueTime
).polls
) the task list.dueTime
, the task is executed, and it’s removed from the list.List
with a PriorityQueue
to efficiently retrieve the next task to run.Time Complexity:
Space Complexity: O(n), where n is the number of scheduled tasks.
Did this solution help you understand the concept better? Let me know your thoughts in the comments below! Don’t forget to follow us on Instagram @coderz.py for more DSA tips and solutions to ace your coding interviews.
Find the length of the longest absolute path to a file within the abstracted file…
You manage an e-commerce website and need to keep track of the last N order…
You are given a stream of elements that is too large to fit into memory.…
The formula for the area of a circle is given by πr². Use the Monte…
Given an integer k and a string s, write a function to determine the length…
There is a staircase with N steps, and you can ascend either 1 step or…