Реализация будущего интерфейса для общих вычислений
Я реализую интерфейс Future<Collection<Integer>>, чтобы разделить результат некоторого массового вычисления между всеми потоками в приложении.
На самом деле, я намеревался просто поместить экземпляр класса implemetting Future<Collection<Integer>> в объект ApplicationScope так, чтобы любой другой поток, которому нужен результат, просто попросил Future из object и вызвал метод get() на нем, поэтому используя вычисление, выполненное каким-то другим потоком.
Мой вопрос заключается в реализации Метод cancel. Сейчас я бы написал что-то вроде этого:
public class CustomerFutureImpl implements Future<Collection<Integer>>{
private Thread computationThread;
private boolean started;
private boolean cancelled;
private Collection<Integer> computationResult;
private boolean cancel(boolean mayInterruptIfRunning){
if( computationResult != null )
return false;
if( !started ){
cancelled = true;
return true;
} else {
if(mayInterruptIfRunning)
computationThread.interrupt();
}
}
//The rest of the methods
}
Но реализация метода не удовлетворяет документации будущего , потому что нам нужно бросить CancellationException в любой поток, ожидающий результата (вызвал метод get()).
Должен ли я добавить еще одно поле, например private Collection<Thread> waitingForTheResultThreads;, а затем прервать каждый поток из Collection, поймать прерванное исключение, а затем throw new CancellationException()?
1 ответ:
Вообще следует избегать реализации
Futureнапрямую. Код параллелизма очень трудно получить правильно, а фреймворки для распределенного выполнения-особенноExecutorService- обеспечитFutureэкземпляры, ссылающиеся на единицы работы, о которых вы заботитесь.Возможно, вы уже знаете об этом и намеренно создаете новый подобный сервис, но я считаю важным напомнить, что для подавляющего большинства случаев использования вам не нужно определять свой собственный
Futureреализация.Вы можете посмотреть на инструменты параллелизма, предоставляемые Guava, в частности
ListenableFuture, который является подинтерфейсомFuture, предоставляющим дополнительные функции.
Предполагая, что вы действительно хотите определить пользовательский тип
Future, используйте GuavaAbstractFutureреализация как отправная точка, так что вам не придется заново изобретать сложные детали, с которыми вы сталкиваетесь.На ваш конкретный вопрос, если вы посмотрите на осуществление
AbstractFuture.get(), Вы увидите, что он реализован с цикломwhile, который ищетvalue, чтобы стать ненулевым, в это время он вызываетgetDoneValue(), который либо возвращает значение, либо вызываетCancellationException. Таким образом, по существу, каждый поток, блокирующий вызовFuture.get(), опрашивает полеFuture.valueкаждый раз и вызываетCancellationException, если он обнаруживает, чтоFutureбыл отменен. Нет необходимости отслеживатьCollection<Thread>или что-либо в этом роде, так как каждый поток может проверять состояние изFutureнезависимо, и вернуть или бросить по мере необходимости.