运行 时间间隔内最后设置的任务

Run last set Task in time interval

标题可能有点离题,所以这里是扩展问题:

我有一个用户控件,例如 Button。每当我单击该按钮时,昂贵的 Runnable 应该安排在 ScheduledExecutorService 中。因为 Runnable 运行 一些 昂贵的 代码,我的想法是只 运行 所说的 Runnable 如果按钮是 not 在给定的时间间隔内再次按下。如果在所述间隔内再次按下按钮,则计时器应重置,并且在给定延迟后相同的 Runnable 应 运行ning。如果在延迟间隔内没有再次按下按钮,则执行 Runnable

有什么 build-in 方法或者我能以某种方式实现吗?

当前的实现如下所示:

public class RepeatedCallScheduler {

    private long waitForMillis;

    private long systemTimeMillis;

    public RepeatedCallScheduler(long waitForMillis) {
        this.waitForMillis = waitForMillis;
    }

    public void run(Runnable runnable) {
        this.systemTimeMillis = System.currentTimeMillis();

        // Run logic
    }

    public static void main(String[] args) {
        RepeatedCallScheduler scheduler = new RepeatedCallScheduler(500);

        Button button = new Button();
        button.setOnAction(event -> {
            scheduler.run(() -> doSomething());
        });
    }

    private static void doSomething() {
        System.out.println("hello");
    }

}

示例

在此示例中,时间延迟值为 500 毫秒,这意味着最后一次单击按钮后 500 毫秒方法 doSomething() 应该 运行。

我点击按钮的时间(以毫秒为单位)x,第二次我点击的时间是 x + 300。现在第一个点击事件不应该 运行 但在时间 x + 800 调度程序应该 运行 方法 doSomething() 异步,只要在 [=21] 期间没有再次点击按钮=] 和 x + 800

此后程序打印 "hello" 一次,而不是两次。

如我之前所问,有没有一种方法可以使用 ScheduledExecutorService 正确地实现这一点?

private long waitForMillis;

private AtomicInteger taskNo;

private ScheduledExecutorService executorService;

public RepeatedCallScheduler(long waitForMillis) {
    this.waitForMillis = waitForMillis;
    this.taskNo = new AtomicInteger();
    executorService = Executors.newScheduledThreadPool(4); // Whatever you need
}

public void run(Runnable runnable) {

    int no = taskNo.incrementAndGet();

        executorService.schedule(() -> {
            // Check if the task should be executed
            if (no == taskNo.get()) {
                // Logic.. 
            }
        }, waitForMillis, TimeUnit.MILLISECONDS);
}

您可以用容器包装要执行的代码并为其指定一个 ID。如果global id改变了,一个新的任务在执行前进来了,不应该开始。

希望这对你有用:)

每当您安排一些操作时,您都会收到 ScheduledFuture 实例,您可以将其用于 cancel 上一个任务并安排新任务:

private ScheduledFuture<?> task;

button.setOnAction(event -> {
    if (task != null) {
        // change this to true if you want to cancel already running task
        task.cancel(false);
    }
    task = scheduler.schedule(() -> doSomething(), 500, TimeUnit.MILLISECONDS);
});