Я реализую некоторый код, используя инфраструктуру java.util.concurrency. Я буду передавать коллекцию вызываемых объектов классу, который будет выполнять их параллельно. Я пытаюсь найти лучший способ получить каждый ответ безопасным способом. Вот некоторый код, чтобы помочь объяснить, что я делаю:
Сначала я создаю свои Callable
s, которые являются единицами работы, которые должны вызываться параллельно. Например, здесь первая единица работы возвращает String
, а вторая Integer
:
Callable<String> firstCallable = new Callable<String>(){
public String call() {...}
};
Callable<Integer> secondCallable = new Callable<Integer>(){
public Integer call() {...}
};
Теперь я запускаю их в свою структуру, чтобы запустить их параллельно, и хитрость заключается в получении дескриптора к подходящему объекту ответа. Вот реализация, которая работает:
Map<Callable,Object> responseMap = ParallelSender.send(firstCallable,
secondCallable);
, где Object
- это ответ конкретного Callable
. Таким образом, вы можете сделать это:
String firstCallableResponse = (String)responseMap.get(firstCallable);
Integer secondCallableResponse = (Integer)responseMap.get(secondCallable);
Итак, мой вопрос: возможно ли избежать каста при получении с карты? Это не компилируется, но я думаю по этому поводу:
Map<Callable<T>, T> responseMap = ParallelSender.send(...);
String firstCallableResponse = responseMap.get(firstCallable);
так, что возвращаемое значение основано на набранном параметре клавиши Callable
. Меня беспокоит то, что если кто-либо изменит рефакторинг типа возвращаемой единицы работы (скажем, от Integer
до BigDecimal
или чего-либо еще), то приведение от Object
никогда не будет обнаружено автоматическими инструментами рефакторинга и может привести к проблемам во время выполнения.
ЗАКЛЮЧЕНИЕ: Благодаря всем полезным комментариям и обсуждению ниже, я выбрал немного другой такт (хотя Шон Патрик Флойд заслужил верность моему вопросу выше). В итоге я полностью сбросил карту ответов и заполнил объект Callable
ответом. Вот соответствующие фрагменты кода:
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;
}
}
Таким образом, у меня есть абстрактная реализация, которая упаковывает объект Callable, сохраняя ответ. Затем, в моей параллельной обработке я получаю ответ, созданный каждым Будущим, и заполняю AbstractParallelCallable:
for (ParallelFutureTask<Object> future : futures) {
try {
future.getCallableHandle().setResponse(future.get());
} catch(Exception e) {...}
}
, где getCallableHandle возвращает объект AbstractParallelCallable и обертки ParallelFutureTask FutureTask, предоставляя ссылку на объект Callable. После выполнения вызывающий код может сделать это:
Integer theResult = firstCallable.getResponse();