实施反跳在Java中 [英] implementing debounce in Java

查看:120
本文介绍了实施反跳在Java中的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

对于一些code我写,我可以用去抖的一个不错的普遍实施的Java。

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

public interface Callback {
  public void call(Object arg);
}

class Debouncer implements Callback {
    public Debouncer(Callback c, int interval) { ... }

    public void call(Object arg) { 
        // should forward calls with the same arguments to the callback c
        // but batch multiple calls inside `interval` to a single one
    }
}

通话()被称为的间隔毫秒使用相同的参数回调函数应该被称为多次一次。

When call() is called multiple times in interval milliseconds with the same argument the callback function should be called exactly once.

一个可视化的:

Debouncer#call  xxx   x xxxxxxx        xxxxxxxxxxxxxxx
Callback#call      x           x                      x  (interval is 2)

  • 在不(像)这样已经存在的一些Java标准库?
  • 你将如何实现呢?
  • 推荐答案

    请考虑以下线程安全的解决方案。需要注意的是锁粒度是在键的水平,使得仅调用相同的密钥块彼此上。它还处理而呼叫(K)被称为上发生密钥K的期满的情况下。

    Please consider the following thread safe solution. Note that the lock granularity is on the key level, so that only calls on the same key block each other. It also handles the case of an expiration on key K which occurs while call(K) is called.

    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);
              }
            }
          }
        }  
      }
    

    这篇关于实施反跳在Java中的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆