预定执行器:以固定速率轮询结果,如果超时或结果有效则退出
Posted
技术标签:
【中文标题】预定执行器:以固定速率轮询结果,如果超时或结果有效则退出【英文标题】:Scheduled executor: poll for result at fix rate and exit if timeout or result valid 【发布时间】:2014-06-07 05:44:39 【问题描述】:问题: 我需要每隔 10 秒以固定速率调用一个 dao 方法,然后我需要检查结果是否有效,如果是退出,否则继续每 10 秒调用一次该方法,直到我得到有效结果或定义超时(比如说 2 分钟)结束了。
方法: 我想将任务和调度程序逻辑分开,并以这样的方式编写任务,以便具有相似要求的不同类可以使用它。
我能想到的一种方法是定义一个新的轮询任务
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;
然后我们可以定义一个单独的类,它接受池频率和超时,并创建一个调度执行器并提交这个任务
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 并获取结果。 为了以下目的,我不得不使用三个执行器:
-
执行程序以固定间隔运行任务
执行程序在超时结束时停止所有操作
如果在超时之前获得有效结果,执行程序将停止所有操作。
有人可以建议一个更好的方法吗,对于如此微不足道的任务来说这似乎很复杂?
【问题讨论】:
【参考方案1】:让它成为一个自调度的任务。在伪代码中:
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;
这并不复杂,但在您第一次运行/测试时添加大量调试语句,这样您就知道发生了什么。一旦它按预期运行,就很容易重复使用该模式。
【讨论】:
【参考方案2】:一个稍微简单的方法,你不需要为终结者单独的执行器服务,你可以简单地将终结者任务推送到同一个执行器中。
更简单。让PollerTask
将其结果放在BlockingQueue
中。然后让PollingTaskRunner
在BlockingQueue
上执行定时poll
。每当从poll
调用ScheduledFuture.cancel
返回控制权时,因为任务成功或超时。
【讨论】:
以上是关于预定执行器:以固定速率轮询结果,如果超时或结果有效则退出的主要内容,如果未能解决你的问题,请参考以下文章