AFAIK submitting Callable
/Runnable
to ExecutorService
is the way to go if I want to execute resource-heavy code in parallel. Hence my method structure:
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 {
...
}
I have marked 2 spots in the code above in which failures can happen. The options available for error handling are quite different for those 2 cases.
Before submitting the task there can be issues like invalid parameters, some fast pre-processing code that may fail.
I see several ways to signify failure here:
- In case of invalid
params
supplied togetResult
return null immediately. In this case I'll have to check ifgetResult
returned null every time I call it. - Throw checked exceptions instead of the above.
- Instantiate a
Future<Result>
that returns null onget()
request. I would do that with Apache CommonsConcurrentUtils.constantFuture(null)
. In this case I would expectgetResult
to always return some non-nullFuture<Result>
. I like this option more, because it is consistent with the second case.
During task execution I can expect serious errors like lack of memory, corrupted files, unavailable files etc.
- I suppose the better option in my case is to return null, because the result of the task is an object.
- Also, I could throw checked exceptions and handle them in
ThreadPoolExecutor.afterExecute
(as suggested by NiranjanBhat). See Handling exceptions from Java ExecutorService tasks
Which is the better practice (in both cases)?
Perhaps there is a different way to do this or a design pattern I should use?