cod*_*der 5 java multithreading scheduledexecutorservice
问题: 我需要以固定速率(例如每 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 ??
}
}
}
Run Code Online (Sandbox Code Playgroud)
用户只需提供任务的实现和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;
}
Run Code Online (Sandbox Code Playgroud)
现在用户可以等待 pollerExecutor.isDone 返回 true 并获取结果。我必须使用三个执行器来实现以下目的:
有人可以建议一个更好的方法吗,对于这样一个微不足道的任务来说这似乎很复杂?
让它成为一个自我调度的任务。在伪代码中:
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;
}
}
Run Code Online (Sandbox Code Playgroud)
它并不复杂,但在第一次运行/测试时添加大量调试语句,以便您知道发生了什么。一旦按预期运行,就可以轻松地重复使用该模式。