java 47 lines · 9 steps

How a debouncer collapses bursts in Java

A generic debouncer delays an action and cancels pending runs so only the last value in a burst fires.

Explained by highlit
1public final class Debouncer<T> {
2 
3 private final ScheduledExecutorService scheduler =
4 Executors.newSingleThreadScheduledExecutor(runnable -> {
5 Thread thread = new Thread(runnable, "debouncer");
6 thread.setDaemon(true);
7 return thread;
8 });
9 
10 private final long delay;
11 private final TimeUnit unit;
12 private final Consumer<T> action;
13 private final Object lock = new Object();
14 
15 private ScheduledFuture<?> pending;
16 private T latest;
17 
18 public Debouncer(long delay, TimeUnit unit, Consumer<T> action) {
19 this.delay = delay;
20 this.unit = unit;
21 this.action = action;
22 }
23 
24 public void submit(T value) {
25 synchronized (lock) {
26 latest = value;
27 if (pending != null) {
28 pending.cancel(false);
29 }
30 pending = scheduler.schedule(this::fire, delay, unit);
31 }
32 }
33 
34 private void fire() {
35 T value;
36 synchronized (lock) {
37 value = latest;
38 pending = null;
39 latest = null;
40 }
41 action.accept(value);
42 }
43 
44 public void shutdown() {
45 scheduler.shutdownNow();
46 }
47}
01 / 01
STEP 01

Walkthrough

Space play step click any line
Three takeaways
  1. 1Debouncing waits out a quiet period and only acts on the final input of a burst.
  2. 2Cancelling the pending task on each new input is what collapses rapid calls into one.
  3. 3A single daemon scheduler plus a lock keeps timing correct without blocking JVM shutdown.

Related explainers

Share this explainer

Here's the card — post it anywhere.

How a debouncer collapses bursts in Java — share card
Made with highlit — turn any snippet into a walkthrough like this in about a minute.
Explain your code