预定执行程序:以固定速率轮询结果,如果超时或结果有效,则退出 [英] Scheduled executor: poll for result at fix rate and exit if timeout or result valid
问题描述
问题: 我有一个要求以固定速率调用dao方法,例如每10秒调用一次,然后我需要检查结果是否有效(如果存在),否则请每隔10秒继续调用该方法,直到获得有效结果或定义的超时为止(例如2分钟)结束.
Problem: I have a requirement to call a dao method at fix rate say every 10 sec, then I need to check if the result is valid if yes exit, else keep on calling that method every 10 sec till I get a valid result or defined time out (say 2 min) is over.
方法: 我想将任务和调度程序逻辑分开,并编写一种任务,使其可以被具有相似需求的不同类使用.
Approaches: I want to keep the task and scheduler logic separate, and write a task in such a way that it can be used by different classes having similar requirement.
我能想到的一种方法是定义一个新的轮询器任务
One way I can think is to define a new poller task
public abstract class PollerTask<T> implements Runnable {
abstract public boolean isValid(T result);
abstract public T task();
private T result;
private volatile boolean complete;
public boolean isComplete() {
return complete;
}
public T getResult() {
return result;
}
@Override
final public void run() {
result = task();
if (complete = isValid(result)) {
//may be stop scheduler ??
}
}
}
用户只需简单地提供task和isValid的实现;
User need to simply provide implementation of task and isValid;
然后,我们可以定义一个单独的类,该类需要合并频率和超时并创建计划的执行程序并提交此任务
Then we can define a separate class that takes pooling freq and timeout and creates a scheduled executor and submit this task
public class PollerTaskExecutor {
private int pollingFreq;
private int timeout;
private ScheduledExecutorService executor;
private ScheduledExecutorService terminator;
private ExecutorService condition;
private volatile boolean done;
private ScheduledFuture future;
public PollerTaskExecutor(int pollingFreq, int timeout) {
this.pollingFreq = pollingFreq;
this.timeout = timeout;
executor = Executors.newSingleThreadScheduledExecutor();
terminator = Executors.newSingleThreadScheduledExecutor();
condition = Executors.newSingleThreadExecutor();
}
public void submitTaskForPolling(final PollerTask pollerTask) {
future = executor.scheduleAtFixedRate(pollerTask, 0, pollingFreq, TimeUnit.SECONDS);
terminator.schedule(new Runnable() {
@Override
public void run() {
complete();
}
}, timeout, TimeUnit.SECONDS);
condition.execute(new Runnable() {
@Override
public void run() {
if (pollerTask.isComplete()) {
complete();
}
}
});
}
public boolean isDone() {
return done;
}
public void complete() {
future.cancel(false);
executor.shutdown();
terminator.shutdown();
condition.shutdown();
done = true;
}
现在用户可以等到pollerExecutor.isDone返回true并获取结果. 我必须出于以下目的使用三个执行器:
now user can wait till pollerExecutor.isDone returns true and get the result. I had to use three executors for following purposes:
- 执行器以固定间隔运行任务
- 执行器在超时结束时停止所有操作
- 如果超时之前获得有效结果,执行器将全部停止.
有人可以建议一种更好的方法吗,这对于如此琐碎的任务来说似乎很复杂?
Can someone please suggest a better approach, this seems to be complicated for such a trivial task ?
推荐答案
使其成为自调度任务.用伪代码:
Make it a self-scheduling task. In pseudo code:
public class PollingTaskRunner {
...
CountDownLatch doneWait = new CountDownLatch(1);
volatile boolean done;
PollingTaskRunner(Runnable pollingTask, int frequency, int period) {
...
endTime = now + period;
executor.schedule(this, 0);
}
run() {
try {
pollingTask.run();
} catch (Exception e) {
...
}
if (pollingTask.isComplete() || now + frequency > endTime) {
done = true;
doneWait.countDown();
executor.shutdown();
} else {
executor.schedule(this, frequency);
}
}
await() {
doneWait.await();
}
isDone() {
return done;
}
}
它并不那么复杂,但是在您第一次运行/测试时添加大量调试语句,这样您就知道发生了什么.一旦按预期运行,就很容易重用该模式.
It is not that complicated but add plenty of debug statements the first time you run/test this so you know what is going on. Once it is running as intended, it is easy to re-use the pattern.
这篇关于预定执行程序:以固定速率轮询结果,如果超时或结果有效,则退出的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!