运行 时间间隔内最后设置的任务
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);
});
标题可能有点离题,所以这里是扩展问题:
我有一个用户控件,例如 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);
});