Java Machine Coding: Building a Hash-Based Executor for Per-Key Ordering
In Java LLD interviews at companies like Apple and Amazon, concurrency questions often hide strict ordering requirements behind high-throughput expectations. Candidates who over-engineer complex lock hierarchies usually fail, whereas those who use a Hash-Based Executor cleanly solve per-key ordering with minimal effort.
The Mistake Most Candidates Make
- Relying on a global
ThreadPoolExecutorwith coarse-grained locks per key, which causes severe thread contention and overhead under high load. - Implementing fine-grained locks using a dynamic
ConcurrentHashMap, which introduces complex cleanup logic and risks subtle memory leaks or deadlocks. - Defaulting to a single-threaded executor for the entire application, which guarantees sequence but completely destroys parallel throughput across independent keys.
The Right Approach
- Core Mental Model: Route incoming tasks to a fixed array of single-threaded executors deterministically using the task key's hash code.
-
Key Entities/Classes:
HashBasedExecutor,ExecutorService,ThreadFactory. - Why It Beats the Naive Approach: It eliminates shared-state locks while providing strict sequential order per entity and horizontal parallelism across distinct entities.
If you're prepping for interviews, I've been building javalld.com — real machine coding problems with full execution traces.
The Key Insight (Code)
public class HashBasedExecutor {
private final ExecutorService[] pools;
public HashBasedExecutor(int poolCount) {
this.pools = new ExecutorService[poolCount];
Arrays.setAll(pools, i -> Executors.newSingleThreadExecutor());
}
public void submit(Object key, Runnable task) {
int index = Math.abs(key.hashCode() % pools.length);
pools[index].submit(task);
}
}
Key Takeaways
- Lock-Free Execution: Dedicated single-threaded workers execute tasks from private task queues, eliminating synchronized blocks and lock contention entirely.
-
Deterministic Routing: Hashing the routing key (e.g.,
userIdororderId) guarantees every event for a given entity hits the same thread. - Linear Scaling: System throughput scales horizontally with the worker array size without introducing race conditions across non-competing keys.
Full working implementation with execution trace available at https://javalld.com/learn/hash-based-executor
Top comments (0)