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
paramssupplied togetResultreturn null immediately. In this case I'll have to check ifgetResultreturned 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 expectgetResultto 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?