Сам я PHP-разработчик, а на джаве решил пописать для души. Пишу простенькое десктоп-приложение с JavaFX, понадобилось реализовать Debounce для слайдера. Нашёл на StackOverflow такое решение:
public class Debouncer <T> {
private final ScheduledExecutorService sched = Executors.newScheduledThreadPool(1);
private final ConcurrentHashMap<T, TimerTask> delayedMap = new ConcurrentHashMap<T, TimerTask>();
private final Callback<T> callback;
private final int interval;
public Debouncer(Callback<T> c, int interval) {
this.callback = c;
this.interval = interval;
}
public void call(T key) {
TimerTask task = new TimerTask(key);
TimerTask prev;
do {
prev = delayedMap.putIfAbsent(key, task);
if (prev == null)
sched.schedule(task, interval, TimeUnit.MILLISECONDS);
} while (prev != null && !prev.extend()); // Exit only if new task was added to map, or existing task was extended successfully
}
public void terminate() {
sched.shutdownNow();
}
// The task that wakes up when the wait time elapses
private class TimerTask implements Runnable {
private final T key;
private long dueTime;
private final Object lock = new Object();
public TimerTask(T key) {
this.key = key;
extend();
}
public boolean extend() {
synchronized (lock) {
if (dueTime < 0) // Task has been shutdown
return false;
dueTime = System.currentTimeMillis() + interval;
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 {
callback.call(key);
} finally {
delayedMap.remove(key);
}
}
}
}
}
}
Начал разбираться в коде и первое, на что обратил внимание - зачем здесь при вызове метода call передавать ключ, если в классе 1 неизменяемый коллбэк на инстанс? То есть, переиспользовать этот класс с другой логикой можно только созданием нового инстанса. Тут, допустим, я понял - чтобы был ключ для мапы. Но тогда второй вопрос: зачем сама мапа нужна? Для упрощения логики с заменой таска в call и сохранения потокобезопасности?
P.S. сама страничка на SO:
https://stackoverflow.com/questions/4742210/implem...