Java 在时间间隔内运行上次设置的任务
标题可能有点不对劲,所以这里有一个扩展的问题: 我有一个用户控件,例如Java 在时间间隔内运行上次设置的任务,java,java-threads,Java,Java Threads,标题可能有点不对劲,所以这里有一个扩展的问题: 我有一个用户控件,例如按钮。每当我点击按钮时,一个昂贵的Runnable应该在ScheduledExecutorService中调度。因为Runnable运行一些昂贵的代码,所以我的想法是,如果在给定的时间间隔内再次按下按钮,则只运行所述Runnable。如果在所述时间间隔内再次按下该按钮,则定时器应复位,且相同的可运行应在给定延迟后运行。如果在延迟间隔期间未再次按下按钮,则执行Runnable 是否存在某种内置方式,或者我是否能够以某种方式意识到
按钮
。每当我点击按钮时,一个昂贵的Runnable
应该在ScheduledExecutorService
中调度。因为Runnable
运行一些昂贵的代码,所以我的想法是,如果在给定的时间间隔内再次按下按钮,则只运行所述Runnable
。如果在所述时间间隔内再次按下该按钮,则定时器应复位,且相同的可运行
应在给定延迟后运行。如果在延迟间隔期间未再次按下按钮,则执行Runnable
是否存在某种内置方式,或者我是否能够以某种方式意识到这一点
当前的实现如下所示:
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
时,只要在x+300
和x+800
期间未再次单击按钮,调度程序应异步运行方法doSomething()
在此之后,程序只打印一次“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。如果全局id更改,则在执行之前会出现一个新任务,因此不应启动该任务
希望这对您有用:)每当您计划一些操作时,您都会收到
ScheduledFuture
实例,您可以使用该实例来取消以前的任务并计划新任务:
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);
});
private ScheduledFuture任务;
按钮。设置操作(事件->{
如果(任务!=null){
//如果要取消已在运行的任务,请将此更改为true
任务。取消(false);
}
task=scheduler.schedule(()->doSomething(),500,TimeUnit.ms);
});
你能解释一下原子整数的作用吗?我不太明白那个角色。代码工作得很好!由于不同的线程可以访问RepeatedCallScheduler
,因此taskNo
充当全局id存储,告诉调度器要执行哪些任务和跳过哪些任务。它应该是一个AtomicInteger
,以使其线程安全,这意味着每个调用都将获得一个唯一的id。我没有想过这样使用它。尽管它工作得非常好,就像下面的答案一样,我会将下面的一个标记为已接受,因为它更接近我当前的实现。谢谢你的帮助!