Bird
Raised Fist0

Job Scheduler

LLDmediumInterview freq: medium
Choose your preparation mode4 modes available
▶
Class Trace
Step 1/4
Job abstract class

Job is an abstract class holding shared state like id, name, and priority, and defines execute() method.

🎯 Tests whether candidate understands abstract class is used because Job holds instance state which interfaces cannot hold in Java.
public abstract class Job {
    protected String id;
    protected String name;
    protected int priority;
    public abstract void execute();
    public int getPriority() { return priority; }
}
RetryPolicy interface and ExponentialBackoff realization

RetryPolicy defines shouldRetry() as a strategy interface; ExponentialBackoff implements it to provide retry logic.

🎯 Tests Strategy pattern usage and realization relationship; interface used for OCP to allow new retry policies without modifying Job.
public interface RetryPolicy {
    boolean shouldRetry(int attempt);
}
public class ExponentialBackoff implements RetryPolicy {
    public boolean shouldRetry(int attempt) {
        // retry logic
        return attempt < maxRetries;
    }
}
JobScheduler Singleton with volatile instance

JobScheduler is a Singleton with a volatile instance field and synchronized getInstance() method to ensure safe publication.

🎯 Tests understanding of volatile keyword to prevent half-constructed instance visibility and synchronized method for thread-safe lazy init.
public class JobScheduler {
    private static volatile JobScheduler instance;
    private PriorityQueue<Job> jobQueue;
    private JobScheduler() {
        jobQueue = new PriorityQueue<>(Comparator.comparingInt(Job::getPriority));
    }
    public static synchronized JobScheduler getInstance() {
        if (instance == null) {
            instance = new JobScheduler();
        }
        return instance;
    }
    public synchronized void scheduleJob(Job job) {
        jobQueue.offer(job);
    }
}
Composition between JobScheduler and JobExecutor

JobScheduler composes JobExecutor, owning its lifecycle and delegating job execution to it.

🎯 Tests composition relationship where JobExecutor cannot exist independently from JobScheduler, enforcing lifecycle ownership.
public class JobScheduler {
    private JobExecutor executor = new JobExecutor();
    // ...
    public void run() {
        while (!jobQueue.isEmpty()) {
            Job job = jobQueue.poll();
            executor.execute(job);
        }
    }
}
public class JobExecutor {
    public void execute(Job job) {
        job.execute();
    }
}
📐
Class Diagram
Class Diagram
       +----------------+
       | <<Abstract>>   |
       |     Job        |
       +----------------+
       | -id: String    |
       | -name: String  |
       | -priority: int |
       +----------------+
       | +execute():void|
       | +getPriority():int|
       +----------------+
              │
              │ extends
       +----------------+
       | RetryPolicy    |
       +----------------+
       | +shouldRetry():|
       |   boolean      |
       +----------------+
              │
              │ realization
       +----------------+
       | ExponentialBackoff|
       +----------------+
       | +shouldRetry():|
       |   boolean      |
       +----------------+
       
       +----------------+
       | <<Singleton>>  |
       | JobScheduler   |
       +----------------+
       | -instance: JobScheduler volatile|
       | -jobQueue: PriorityQueue<Job>   |
       +----------------+
       | +getInstance():JobScheduler [sync]|
       | +scheduleJob(Job):void [sync]   |
       +----------------+
              │ ◆ composition
       +----------------+
       | JobExecutor    |
       +----------------+
       | +execute(Job):void|
       +----------------+

This diagram highlights four key Java design decisions in the Job Scheduler system. First, Job is an abstract class holding shared state like id and priority, which interfaces cannot hold, enforcing the use of abstract class for shared behavior and state. Second, RetryPolicy is an interface realized by ExponentialBackoff, demonstrating the Strategy pattern to allow flexible retry policies without modifying existing code, adhering to the Open-Closed Principle. Third, JobScheduler is implemented as a thread-safe Singleton using a volatile instance field and synchronized getInstance() method to prevent unsafe publication and ensure only one instance exists. Fourth, JobScheduler composes JobExecutor, owning its lifecycle, which enforces strong lifecycle management and clear separation of concerns. These decisions collectively ensure extensibility, thread safety, and maintainable design.

Primary Focus

✓ Abstract class state vs Interface + Singleton volatile + Composition lifecycle + Strategy pattern OCP

Practice

(1/5)
1. A logging framework has a Logger class with a private constructor and a static synchronized getInstance() method returning the single instance. Which design pattern is applied here and why is it the correct choice?
easy
A. Factory pattern, because it controls object creation centrally.
B. Prototype pattern, to clone Logger instances efficiently.
C. Builder pattern, to construct Logger with complex configurations.
D. Singleton pattern, ensuring only one Logger instance exists globally.

Solution

  1. Step 1: Identify the pattern from private constructor and static getInstance()

    The private constructor prevents external instantiation, and the static synchronized getInstance() ensures a single shared instance, which matches the Singleton pattern.
  2. Step 2: Why Singleton is correct here

    Logging frameworks require a single global Logger instance to coordinate log output consistently. Factory, Builder, and Prototype patterns do not enforce single instance semantics.
  3. Final Answer:

    Option D -> Option D
  4. Quick Check:

    Private constructor + static synchronized getInstance() -> Singleton [check]
Hint: Private constructor + static getInstance() -> Singleton [check]
Common Mistakes:
2. In the Elevator System, should the Elevator class implement an interface or extend an abstract class to represent different elevator types (e.g., passenger, freight)? Consider that elevators share common state and behavior but also have type-specific logic.
easy
A. Use an abstract class, because elevators share common state and partial behavior implementations.
B. Use an interface, because elevators only share behavior signatures, not state.
C. Use a concrete class, because inheritance is unnecessary for elevator types.
D. Use multiple interfaces, one per behavior, to avoid state duplication.

Solution

  1. Step 1: Analyze shared state and behavior

    Elevators share common fields like currentFloor, direction, and doorStatus, plus some implemented methods.
  2. Step 2: Abstract class fits shared state and partial behavior

    Abstract class allows code reuse and enforces common state, while subclasses override type-specific logic.
  3. Final Answer:

    Option A -> Option A
  4. Quick Check:

    Abstract class supports shared state and behavior [check]
Hint: Abstract class for shared state; interface for pure behavior [check]
Common Mistakes:
3. In the Food Ordering System, the KitchenQueue class has a parkOrder() method that checks if a slot is available before assigning an order. Without synchronization on parkOrder(), which exact thread interleaving causes double-booking of the same slot?
medium
A. Thread 1 and Thread 2 both call parkOrder() simultaneously and the JVM throws an exception.
B. Thread 1 checks slot availability -> true, context switch before assignment; Thread 2 checks availability -> true, both assign same slot.
C. Thread 1 assigns slot, then Thread 2 waits for Thread 1 to finish before assigning next slot.
D. Thread 1 and Thread 2 both wait on a lock, causing deadlock and no assignment.

Solution

  1. Step 1: Identify the check-then-act race condition

    Without synchronization, Thread 1 reads slot as available but is preempted before assignment; Thread 2 also reads available and proceeds.
  2. Step 2: Both threads assign the same slot leading to double-booking

    Because the availability check and assignment are not atomic, both threads assign the same slot concurrently.
  3. Final Answer:

    Option B -> Option B
  4. Quick Check:

    Check-then-act gap without sync -> double assignment [check]
Hint: Check availability -> context switch -> both assign same slot [check]
Common Mistakes:
4. In the traffic light system, the parkVehicle() method is not synchronized. Which exact sequence of Thread 1 and Thread 2 calls causes double-booking of the same parking spot?
medium
A. Thread 1 checks spot availability -> true, context switch; Thread 2 checks availability -> true; both park simultaneously
B. Thread 1 parks vehicle, Thread 2 parks vehicle after Thread 1 completes
C. Thread 1 parks vehicle, Thread 2 waits for lock and then parks
D. Thread 1 releases spot, Thread 2 parks immediately after

Solution

  1. Step 1: Identify check-then-act race condition

    Without synchronization, Thread 1 reads spot as available but before marking it occupied, context switches to Thread 2 which also reads available.
  2. Step 2: Both threads proceed to park, causing double-booking

    Both threads act on stale availability info, violating mutual exclusion.
  3. Final Answer:

    Option A -> Option A
  4. Quick Check:

    Unsynchronized check-then-act -> double-booking race [check]
Hint: Check-then-act gap -> both see available -> double-book [check]
Common Mistakes:
5. Facebook wants to add ElectricCar users who require ChargingSpot support in the Vehicle and ParkingSpot hierarchy. What is the minimum change to the current design to support this without modifying existing classes?
hard
A. Create a new ElectricVehicleManager class that handles electric cars separately from existing classes.
B. Modify Vehicle and ParkingSpot classes to add electric-specific fields and logic.
C. Add ELECTRIC_CAR to VehicleType enum, CHARGING to SpotType, create ElectricCar subclass, and update compatibility map externally.
D. Add boolean isElectric flag to Vehicle and ParkingSpot and handle logic with conditionals.

Solution

  1. Step 1: Identify extensibility without modifying existing classes

    Adding new enum values and subclasses extends functionality without changing existing code.
  2. Step 2: Use external compatibility map update

    Updating the compatibility map externally avoids modifying existing class logic, preserving OCP.
  3. Final Answer:

    Option C -> Option C
  4. Quick Check:

    New enums + subclass + external map update -> minimal change [check]
Hint: Add enums + subclass + external map, no existing class change [check]
Common Mistakes:
Recommended

Ready to prove it?

Pass the test and this pattern moves unknown strong while earning +1 Grip toward your certificate.

10 questions~5 mineasy hard