我当前面临一个特定的问题,我不确定该如何解决。让我 简要描述这个问题:
仅使用“老式”意味着我想出了以下解决方案(为简化起见,部分伪代码)
//No exception handling to simplify method
public ComplexValuePart mainMethod(int id) {
//Other code executed before
int maxAmountTries = 5;
int waitTime = 2000;
int counter = 0;
boolean conditionFulfilled = false;
ComplexValue cv = null;
while (counter++ < maxAmountTries && !conditionFulfilled) {
cv = calculatingMethod(id);
if (cv.conditionHolds()) {
conditionFulfilled = true;
} else {
Thread.sleep(waitTime);
}
}
if (counter == maxAmountTries && !conditionFulfilled) {
//report error
}
//Continue processing with cv
return doThingsWithCV(cv);
}
public ComplexValue calculatingMethod(int id) {
//Implementation not relevant here
}
但是,使用Java 8(现在这是我的限制),我认为可能还有其他/更好的解决方案?
作为替代方案,我使用ScheduledExecutorService提出了一些建议,例如:
public void mainMethod(int id) {
//Other code executed before
ScheduledExecutorService service = Executors.newScheduledThreadPool(1);
Future<?> future = service.scheduleAtFixedRate(new Runnable() {
@Override
public void run() {
ComplexValue cv = calculatingMethod(id);
if (cv.conditionHolds()) {
//shutdown service including awaitTermination
}
}
}, 0, 2, TimeUnit.SECONDS);
try {
future.get(20, TimeUnit.SECONDS);
} catch (InterruptedException | ExecutionException | TimeoutException e) {
//shutdown service including awaitTermination
}
//Continue processing with cv - How can I access cv here?
}
要返回ComplexValue
,我想我需要使用Callable
而不是Runnable
吗?我可以用Callable
来做到这一点吗?
此外,即使之前服务执行中的条件确定,也总是会遇到超时问题。
在这种情况下,我不知道对于实现这样一个非常简单的任务而言,这是否有点“过多”?
与普通的Thread sleep
相比,这种解决方案有什么好处?
实现该部分是否缺少一些Java 8功能?
注意:在此循环中,我不必并行执行不同的任务。主方法的执行不得继续
直到超时到期或所需的结果在那里-因此,不会执行async
。
适当的方法需要根据服务调用的响应返回一些数据。
答案 0 :(得分:2)
我改用TimerTask。它每“ waitTime”毫秒重复执行“ run”方法。您可以通过调用“ timer.cancel()”来指定何时停止重复此任务。
public void mainMethod(int id) {
Timer timer = new Timer();
timer.schedule(new TimerTask() {
int counter = 0;
@Override
public void run() {
cv = calculatingMethod(id);
if (cv.conditionHolds() || counter++ > countLimit) {
// conditionFulfilled = true;
timer.cancel();
}
}
}, 0, waitTime);
}
答案 1 :(得分:1)
final long deadline = System.currentTimeMillis() + TIMEOUT_MS;
boolean done;
Result result;
do {
result = doSomething();
done = resultIsOk(result);
if ( !done ) {
final long msRemaining = deadline - System.currentTimeMillis();
if ( msRemaining > 0 ) {
Thread.sleep(Math.min(msRemaining, RETRY_WAIT_TIME_MS);
} else {
done = true;
}
}
} while (!done);
if ( !resultIsOk(result) ) {
// Error or something.
}
此代码将继续调用doSomething()
,直到返回期望值或 TIMEOUT_MS
毫秒为止。假设doSomething()
快速返回,则花费的时间永远不会超过TIMEOUT_MS
(可能还有几毫秒)。另外,重试之间的延迟是恒定的,并且与doSomething()
的运行时间无关(即使doSomething()
运行1.9秒也会每2秒重试一次),而最坏的情况是{{ 1}}和一次致电TIMEOUT_MS
所花费的时间。
在其自己的类doSomething()
中实现等待/超时逻辑可能是有益的。然后,您可以为给定的超时时间创建一个实例,并将其传递到不同的层,这样,即使是最低层(例如,网络IO)也可以适当地设置其超时值,以不超过应用程序逻辑顶层定义的期限。 / p>
将Timeout
类与多态Timeout
组合在一起,您可以使用非常灵活的方式来指定和处理许多不同的场景。
使用lambda,您甚至可以创建完全重试逻辑的完全通用封装,例如
RetryStrategies