java
36 lines · 6 steps
Coalescing duplicate requests in Java
How a ConcurrentHashMap of in-flight futures collapses concurrent calls for the same key into one load.
Explained by
highlit
1public class RequestCoalescer<K, V> {
2
3 private final ConcurrentHashMap<K, CompletableFuture<V>> inFlight = new ConcurrentHashMap<>();
4 private final Function<K, V> loader;
5 private final Executor executor;
6
7 public RequestCoalescer(Function<K, V> loader, Executor executor) {
8 this.loader = loader;
9 this.executor = executor;
10 }
11
12 public CompletableFuture<V> get(K key) {
13 CompletableFuture<V> existing = inFlight.get(key);
14 if (existing != null) {
15 return existing;
16 }
17
18 CompletableFuture<V> created = new CompletableFuture<>();
19 CompletableFuture<V> raced = inFlight.putIfAbsent(key, created);
20 if (raced != null) {
21 return raced;
22 }
23
24 CompletableFuture.supplyAsync(() -> loader.apply(key), executor)
25 .whenComplete((value, error) -> {
26 inFlight.remove(key, created);
27 if (error != null) {
28 created.completeExceptionally(error);
29 } else {
30 created.complete(value);
31 }
32 });
33
34 return created;
35 }
36}
01 / 01
STEP 01
‹ swipe to step through ›
Walkthrough
Space play
←→ step
click any line
Three takeaways
- 1Sharing a future per key lets many callers await one computation instead of triggering redundant work.
- 2putIfAbsent turns a check-then-act race into a single atomic claim, so exactly one caller starts the load.
- 3Removing the entry on completion keeps the map bounded and lets future callers trigger a fresh load.
Related explainers
python
from fastapi import FastAPI, WebSocket, WebSocketDisconnect app = FastAPI()
Building a WebSocket chat with FastAPI
websockets
broadcast
connection-management
Intermediate
9 steps
java
@Component @Converter public class EncryptedStringConverter implements AttributeConverter<String, String> {
Transparent column encryption in Spring & JPA
encryption
aes-gcm
jpa-converter
Advanced
10 steps
rust
use axum::{ extract::{Path, State}, response::sse::{Event, KeepAlive, Sse}, };
Streaming import progress with SSE in Axum
server-sent-events
streams
watch-channel
Advanced
7 steps
java
package com.acme.billing.config; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.context.properties.ConfigurationProperties;
Feature-flagged beans with Spring @ConditionalOnProperty
feature-flags
conditional-beans
strategy-pattern
Intermediate
5 steps
javascript
import { useState, useEffect, useCallback, useRef } from 'react'; const cache = new Map(); const inflight = new Map();
Building a stale-while-revalidate hook in React
caching
request-deduplication
custom-hooks
Advanced
10 steps
go
func (w *Watcher) resetDebounce(d time.Duration) { if !w.timer.Stop() { select { case <-w.timer.C:
Debouncing a stream of events in Go
debounce
timers
channels
Advanced
7 steps
Share this explainer
Here's the card — post it anywhere.
Made with highlit — turn any snippet into a walkthrough like this in about a minute.
Explain your code
Embed this explainer
Drop the interactive walkthrough into a blog or docs. Views never cost a credit.
<iframe src="https://highlit.co/explainers/coalescing-duplicate-requests-in-java-explained-java-82dc/embed?autoplay=1" width="100%" height="520" loading="lazy" style="border:0"></iframe>
Autoplay is on by default — add ?autoplay=0 to start paused.