小知识,大挑战!本文正在参与“程序员必备小知识”创作活动。
概述
目前在开发一个文档监控类工具时遇到一个问题,希望在文档编写过程中不对文档做备份,而在文档编写结束时再备份,这就需要一个防抖函数。
防抖函数,就是指触发事件后在n 秒内函数只能执行一次,如果在n 秒内又触发了事件,则会重新计算函数执行时间。 简单的说,当一个动作连续触发,则只执行最后一次。
实现
我们可以使用ScheduledExecutorService的schedule方法实现, 为每个任务分配一个唯一的 key,使用ConcurrentHashMap来存储 key-future,使用future的 cancel 方法来取消线程任务
package org.example.simple;
import java.util.concurrent.*;
/**
* @author Catch
* @since 2021-10-29
*/
public class Debounce {
private static final ScheduledExecutorService SCHEDULE = Executors.newSingleThreadScheduledExecutor();
// 使用 ConcurrentHashMap 来存储 Future
private static final ConcurrentHashMap<Object, Future<?>> DELAYED_MAP = new ConcurrentHashMap<>();
/**
* 抖动函数
*/
public static void debounce(final Object key, final Runnable runnable, long delay, TimeUnit unit) {
final Future<?> prev = DELAYED_MAP.put(key, SCHEDULE.schedule(() -> {
try {
runnable.run();
} finally {
// 如果任务运行完,则从 map 中移除
DELAYED_MAP.remove(key);
}
}, delay, unit));
// 如果任务还没运行,则取消任务
if (prev != null) {
prev.cancel(true);
}
}
/**
* 停止运行
*/
public static void shutdown() {
SCHEDULE.shutdownNow();
}
public static void main(String[] args) {
// 1,2 为每个任务的唯一 key
Debounce.debounce("1", () -> {System.out.println(11);}, 3, TimeUnit.SECONDS);
Debounce.debounce("1", () -> {System.out.println(22);}, 3, TimeUnit.SECONDS);
Debounce.debounce("1", () -> {System.out.println(33);}, 3, TimeUnit.SECONDS);
Debounce.debounce("2", () -> {System.out.println(44);}, 3, TimeUnit.SECONDS);
Debounce.debounce("2", () -> {System.out.println(44);}, 3, TimeUnit.SECONDS);
Debounce.debounce("2", () -> {System.out.println(44);}, 3, TimeUnit.SECONDS);
}
}