gpt4 book ai didi

java - 装饰 Java 的可调用对象以添加行为

转载 作者:行者123 更新时间:2023-11-30 03:03:33 28 4
gpt4 key购买 nike

假设我们有可能需要长时间运行的任务:

public class LongRunningTask {
public ReturnType doSomething() {
...
}
}

并且我们希望同时运行许多这样的任务。

所以,我有我的可调用对象:

public class LongRunningCallable implements Callable<LongRunningTask> {
private final LongRunningTask task;
...
public ReturnType call() {
return task.doSomething();
}
...
}

现在,由于这可能真的会持续很长时间,我想将其限制为仅运行一定数量。所以,我可能会做这样的事情:

public class InterruptibleCallable<T> implements Callable<T> {
protected final long timeout;
protected final TimeUnit timeUnit;
protected final Callable<T> callable;

public InterruptibleCallable(long timeout, TimeUnit timeUnit, Callable<T> callable) {
this.timeout = timeout;
this.timeUnit = timeUnit;
this.callable = callable;
}

@Override
public T call() throws Exception {

ExecutorService executorService = Executors.newSingleThreadExecutor();

T result = null;

try {
result = executorService.submit(callable).get(timeout, timeUnit);
} catch (InterruptedException e) {
LOGGER.error("Callable: " + callable.toString() + " was interrupted");
throw e;
} catch (ExecutionException e) {
throw e;
} catch (TimeoutException e) {
LOGGER.warn("Callable: " + callable.toString() + " timed out after " + timeout + " " + timeUnit);
throw e;
} finally {
executorService.shutdown();
}

return result;
}
}

没关系,但现在我还想包装它,以便在遇到异常时它可以重试(有延迟):

public class RetryableCallable<T> implements Callable<T> {
private final long delay;
private final TimeUnit timeUnit;
private final Callable<T> callable;

@Override
public T call() throws Exception {
T result = null;

try {
ExecutorService executorService = Executors.newSingleThreadExecutor();
result = executorService.submit(this.callable).get();
} catch (Exception e) {
ScheduledExecutorService executorService = Executors.newSingleThreadScheduledExecutor();
result = executorService.schedule(this.callable, delay, timeUnit).get();
}

return result;
}
}

现在,我的问题:

  1. 是否已经有一个库可以提供此功能(或超集)?

  2. 这是一个好的设计吗,特别是创建另一个执行器并在每个包装器中提交一个可调用函数,为什么?

  3. 从设计模式的角度和性能的角度来看,解决这个问题的最佳方法是什么?

谢谢:D

最佳答案

RetryableCallable 包裹在 InterruptibleCallable 周围,后者包裹 LongRunningTask 并在每个 RetryableCallable 执行上创建两个额外的执行器,这是不好的。

RetryableCallable捕获TimeoutException时,通常它不应该再次运行相同的任务。这有点令人困惑,因为如果任务被超时“杀死”,为什么你想再运行一次呢?另外为什么需要在这里创建另一个执行器?保持简单

public class RetryableCallable<T> implements Callable<T> {
private int retries = 3;

@Override
public T call() throws Exception {
while (retries-- > 0) {
try {
return callable.call();
} catch (InterruptedException e) {
LOGGER.error("Callable: " + callable.toString() + " was interrupted");
throw e;
} catch (TimeoutException e) {
LOGGER.warn("Callable: " + callable.toString() + " timed out after " + timeout + " " + timeUnit);
throw e;
} catch (Exception e) {
LOGGER.warn("Callable: " + callable.toString() + " failed");
}
}
throw new IllegalStateException();//or return null
}
}

并且它不应该使用超时和延迟,它是 RetryableCallable 但不是 RetryableCallableWithDelayAndTimeoutAndSomethingElse

如果你想限制任务的执行时间,我至少看到 4 种好方法:

  • 在提交的线程中调用get(time, timeunit)
  • 限制任务在 call() 函数内的执行时间,例如通过“定期”检查我们是否还有更多时间。
  • 创建您自己的执行程序类,其中包含自定义执行程序和一个线程 Auditor,该类将接受一些 TimeLimitedCallable,它扩展了 Callable 并具有 int getTimeLimit() 函数。 Auditor 将控制所有实现 TimeLimitedCallable 的运行任务的时间范围。
  • 为“任务的审核员”创建一个单独的执行程序,并在将一个(或一堆)具有业务逻辑的任务提交到主执行程序中后 - 创建审核任务并将其提交到单独的执行程序中。

关于java - 装饰 Java 的可调用对象以添加行为,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35366001/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com