I'm implementing some code using the java.util.concurrency framework. I will be passing a collection of callables to a class which will execute them in parallel. I'm trying to work out the best way of getting a hold of each response in a type safe manner. Here's some code to help explain what I'm doing:
First I create my Callable
s, which are units of work to be called in parallel. For example, here the first unit of work returns a String
and the second an Integer
:
Callable<String> firstCallable = new Callable<String>(){
public String call() {...}
};
Callable<Integer> secondCallable = new Callable<Integer>(){
public Integer call() {...}
};
Now I fire them into my framework to run them in parallel and the trick is getting a handle to the appropiate response Object. Here's an implementation that works:
Map<Callable,Object> responseMap = ParallelSender.send(firstCallable,
secondCallable);
where Object
is the response of a particular Callable
. Thus, you can do this:
String firstCallableResponse = (String)responseMap.get(firstCallable);
Integer secondCallableResponse = (Integer)responseMap.get(secondCallable);
So my question is, is it possible to avoid casting when fetching from the Map? This doesn't compile, but I'm thinking along these lines:
Map<Callable<T>, T> responseMap = ParallelSender.send(...);
String firstCallableResponse = responseMap.get(firstCallable);
such that the value returned is based on the typed parameter of the Callable
key. My concern is that if anyone refactors the return type of the unit of work (say from Integer
to BigDecimal
or whatever) then the cast from Object
will never be caught by automatic refactor tools and could lead to runtime issues.
CONCLUSION: Thanks to all the helpful comments and discussion below, I have taken a slightly different tact (though credited Sean Patrick Floyd with a correct to my question above). I ended up dropping the response map alltogether and populating the Callable
object with the response. Here are the relevant code snippets:
public abstract class AbstractParallelCallable<V> implements Callable<V> {
/** The response generated by the Call method of this class. */
private V callableResponse;
public V getResponse() {
return callableResponse;
}
public void setResponse(V response) {
callableResponse = response;
}
}
Thus, I have an abstract implementation which wrappers the Callable object by storing the response. Next,in my parallel processing I get the response each Future created and populate the AbstractParallelCallable:
for (ParallelFutureTask<Object> future : futures) {
try {
future.getCallableHandle().setResponse(future.get());
} catch(Exception e) {...}
}
where getCallableHandle returns the AbstractParallelCallable object and ParallelFutureTask wrappers FutureTask by providing a reference to the Callable object. After execution, the calling code can then do this:
Integer theResult = firstCallable.getResponse();