Java 防抖动函数的实现

2,078 阅读1分钟

小知识,大挑战!本文正在参与“程序员必备小知识”创作活动。

概述

目前在开发一个文档监控类工具时遇到一个问题,希望在文档编写过程中不对文档做备份,而在文档编写结束时再备份,这就需要一个防抖函数。

防抖函数,就是指触发事件后在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);
    }

}