如果我想并行执行资源密集型代码,那么AFAIK向Callable
提交Runnable
/ ExecutorService
是可行的方法。因此我的方法结构:
public class ServiceClass {
protected final ExecutorService executorService = Executors.newCachedThreadPool();
public Future<Result> getResult(Object params) {
if (params == null) {
return null; // In situations like this the method should fail
}
// Do other fast pre-processing stuff
return executorService.submit(new CallProcessResult(params));
}
private class CallProcessResult implements Callable<Result> {
private Object params;
public CallProcessResult(Object params) {
this.params = params;
}
@Override
public Result call() throws Exception {
// Compute result for given params
// Failure may happen here too!
return result;
}
}
}
public class Result {
...
}
我在上面的代码中标记了2个可能发生故障的位置。对于这两种情况,可用于错误处理的选项是完全不同的。
在提交任务之前,可能会出现无效参数,某些可能失败的快速预处理代码等问题。
我在这里看到了几种表示失败的方法:
params
的{{1}}无效,则立即返回null。在这种情况下,我每次调用时都要检查getResult
是否返回null。getResult
,在Future<Result>
请求中返回null。我会用Apache Commons get()
做到这一点。在这种情况下,我希望ConcurrentUtils.constantFuture(null)
始终返回一些非空getResult
。我更喜欢这个选项,因为它与第二种情况一致。在执行任务期间我可能会遇到严重错误,例如内存不足,文件损坏,文件不可用等等。
Future<Result>
处理它们(如NiranjanBhat所建议的那样)。请参阅Handling exceptions from Java ExecutorService tasks 哪种更好的做法(在两种情况下都是这样)?
也许有不同的方法来做这个或我应该使用的设计模式?
答案 0 :(得分:9)
我建议在任务处理过程中失败,你只需抛出一个适当的异常。不要在执行程序中为此添加任何特殊处理。将会发生的是它将被捕获并存储在Future
中。当Future
的{{1}}方法被调用时,它会抛出get
,然后ExecutionException
的调用者可以解包并处理它。这基本上是将正常的异常处理转换为get
/ Callable
范例的方式。这看起来像这样:
Future
鉴于 Future<Result> futureResult = serviceClass.getResult("foo");
try {
Result result = futureResult.get();
// do something with result
}
catch (ExecutionException ee) {
Throwable e = ee.getCause();
// do something with e
}
的调用者必须对get
进行此处理,您可以利用它来处理提交期间的失败。为此,您可以构造一个类似于Apache Commons ExecutionException
的{{1}},但它会抛出给定的异常而不是返回给定的值。我不认为JDK中有类似的东西,但写起来很简单(如果单调乏味):
Future
这有点狡猾 - 你在同步调用的方法中失败了,并且在异步调用的方法中使它看起来像一个失败。您正在将处理错误的负担从实际导致它的代码转移到稍后运行的某些代码。但是,它确实意味着您可以在一个地方拥有所有故障处理代码;这可能足以让它变得有价值。
答案 1 :(得分:2)
您可以使用afterExecute方法。这是在ThreadPoolExecutor中定义的,您需要覆盖它。
在完成每个任务的执行后调用此方法。您将在此回调方法中获取任务实例。您可以在任务中的某个变量中记录错误,并使用此方法访问它。