2013-08-13 2 views
1

Я работаю над проектом, у которого есть пул потоков, которому он представляет задачи. Каждая задача - это цепочка, так сказать. Когда задача выполняется, она выполняет то, что ей нужно, а затем проверяет результат. Каждая из этих задач содержит карту результатов (которая представляет собой просто перечисление) и дополнительные задачи. Они вызываются внутри одного потока, и цикл повторяется до тех пор, пока не будет больше задач, после чего он вернется в цепочку, добавив каждый результат в коллекцию и вернув это в основной поток. Q & D Пример:Java Future <T>, TimeoutException и получение частичных результатов

public abstract class MyCallable implements Callable<MyResponse> { 

private Map<ResponseEnum, List<MyCallable>> callbacks; 

public List<MyResponse> call() { 
    List<MyResponse> resp = new ArrayList<MyResponse>(); 
    try{ 
     //Run the process method and collect the result 
     MyResponse response = process(); 
     List<MyCallable> next = callbacks.get(response.getResult()); 

     if (next != null && !next.isEmpty()){ 
      //Run within same thread, return results 
      for (MyCallable m : next){ 
       resp.addAll(m.call(); 
      } 
      return resp; 
     } else { 
      //No more responses, pass them back up the chain 
      resp.add(response); 
      return list; 
     } 
    //Anything goes wrong, we catch it here and wrap it in a response 
    } catch (Exception e){ 
     resp.add(new MyExceptionResponse(e)); 
     return resp; 
    } 
} 

//Implemented by all child classes, does the actual work 
public abstract MyResponse process() throws Exception; 

Имейте в виду, что это также опытный образец, который я до сих пор на самом деле не проверял, так что я знаю, что это не может быть совершенным или обязательно полностью осуществимо.

У меня есть проблема: задача добавлена ​​в пул потоков и начинает выполнение. В основном потоке создается Будущее и на него вызывается функция .get (N, TimeUnit) для извлечения результата. Что делать, если эта задача не работает? Мы получаем исключение TimeoutException. Теперь, в блоке try/catch я мог бы отменить Будущее, но есть ли способ отменить будущее и извлечь результаты, по крайней мере, насколько они идут? Три задачи, возможно, выполнили и вернули результаты до того, как четвертый остановился. Try/catch в MyCallable должен возвращать результат и нажимать его на цепочку, если есть исключение (Ie, InterruptedException, когда вызывается .cancel (true)), но возможно ли получить этот результат?

Конечно, если я собираюсь сделать это совершенно неправильно в первую очередь, это было бы также полезно знать. Это мой первый большой набег на многопоточность.

EDIT: Хорошо, с учетом этого, оболочка была помещена вокруг класса MyCallable. Обертка реализует Callable и возвращает коллекцию. Коллекция передается по цепочке объектов MyCallable и добавляются результаты, поэтому, если время ожидания Future.get, мы можем получить сбор и получить частичные результаты.

Однако это вызывает потенциальное состояние гонки. Если текущий вызов MyCallable ожидает внешнего сервиса, то операция Future.cancel (true) вызовет InterruptedException в MyCallable. Это поймано, и исключение обернуто в объект ответа и добавлено в коллекцию. Дело в том, что если основной поток отменяет будущее, синхронизируется на обертке или коллекции в оболочке, а затем получает коллекцию, это создаст условие гонки между получением коллекции и блоком try/catch в добавлении MyCallable завернутое исключение из коллекции? Или будет ли основной поток ждать улавливания исключения и затем выполнить следующую строку?

ответ

2

В тот момент, когда вы получите ваш TimeoutException, задача представляется Исполнитель Услуга Весело выйдут на своем пути: это только ваш ждет, который получил исключение. Это предположительно означает, что карта результатов все еще заполняется.

Что вы можете сделать, это использовать параллельную карту и безопасно извлекать любые результаты, имеющиеся после истечения таймаута.

+0

Карта используется только в качестве дерева решений, чтобы получить следующий MyCallable. Когда текущий результат приходит, он используется для получения следующего MyCallable с карты и выполнения этого и т. Д. Возможно, возможно сделать доступным набор результатов, что может быть необходимо, так как я не могу получить результаты из отмененного Будущего без моего собственного будущего класса. – user1017413

+0

Просто не используйте возвращаемое значение в качестве канала связи. Храните накопленные результаты в том месте, где вы можете получить их независимо от механизма Future. –

+0

Определенно выполнимый, я полагаю, но теперь, чтобы найти лучший способ.Возможно, возьмите эти объекты MyCallable и поместите их в оболочку, которая сама реализует Callable, которая затем вызывает MyCallables и передает им коллекцию, которая заполняется ... – user1017413