实施反跳在Java中Java

由网友(微信扫描或直接搜索关注“腾牛个性网”微信公众号,方便随时查看)分享简介:对于一些code我写,我可以用去抖的一个不错的普遍实施的Java。For some code I'm writing I could use a nice general implementation of debounce in Java.public interface Callback {public voi...

对于一些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);
          }
        }
      }
    }  
  }
阅读全文

相关推荐

最新文章