Реализация будущего интерфейса для общих вычислений
Я реализую интерфейс 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
независимо, и вернуть или бросить по мере необходимости.