implementing debounce in Java

前端 未结 8 639
心在旅途
心在旅途 2020-11-30 04:09

For some code I\'m writing I could use a nice general implementation of debounce in Java.

public interface Callback {
  public void call(Object          


        
8条回答
  •  -上瘾入骨i
    2020-11-30 04:40

    I've updated @Eyal's answer to be able to configure debouncing time in each call, and use runnable code block instead of callback:

    import java.util.concurrent.ConcurrentHashMap;
    import java.util.concurrent.Executors;
    import java.util.concurrent.ScheduledExecutorService;
    import java.util.concurrent.TimeUnit;
    
    public class Debouncer {
    
        private final ScheduledExecutorService sched = Executors.newScheduledThreadPool(1);
        private final ConcurrentHashMap delayedMap = new ConcurrentHashMap();
    
        public Debouncer() {
        }
    
        public void call(T key, Runnable runnable, int interval, TimeUnit timeUnit) {
            TimerTask task = new TimerTask(key, runnable, interval, timeUnit);
    
            TimerTask prev;
            do {
                prev = delayedMap.putIfAbsent(key, task);
                if (prev == null)
                    sched.schedule(task, interval, timeUnit);
            } while (prev != null && !prev.extend());
        }
    
        public void terminate() {
            sched.shutdownNow();
        }
    
        private class TimerTask implements Runnable {
            private final T key;
            private final Runnable runnable;
            private final int interval;
            private final TimeUnit timeUnit;
            private long dueTime;
            private final Object lock = new Object();
    
            public TimerTask(T key, Runnable runnable, int interval, TimeUnit timeUnit) {
                this.key = key;
                this.runnable = runnable;
                this.interval = interval;
                this.timeUnit = timeUnit;
                extend();
            }
    
            public boolean extend() {
                synchronized (lock) {
                    if (dueTime < 0)
                        return false;
                    dueTime = System.currentTimeMillis() + TimeUnit.MILLISECONDS.convert(interval, timeUnit);
                    return true;
                }
            }
    
            public void run() {
                synchronized (lock) {
                    long remaining = dueTime - System.currentTimeMillis();
                    if (remaining > 0) { // Re-schedule task
                        sched.schedule(this, remaining, TimeUnit.MILLISECONDS);
                    } else { // Mark as terminated and invoke callback
                        dueTime = -1;
                        try {
                            runnable.run();
                        } finally {
                            delayedMap.remove(key);
                        }
                    }
                }
            }
        }
    }
    

提交回复
热议问题