Вызывается с помощью цикла while

Мне нужно предоставить код, который с помощью ExecutorService, Callable и Future будет выполнять некоторые вычисления и печатать частичные результаты до тех пор, пока не будет достигнуто определенное условие. Первое, что приходит мне в голову - это использовать цикл while. К сожалению, насколько я понимаю, ExecutorService.get() ждет, пока задача не будет выполнена, поэтому я не могу сделать что-то вроде (псевдокод):

public Object call() throws Exception {
  try {
    while(!condition)           {
      //perform calc
      return partialCalculationResult;
    }
  }
  catch(InterruptedException e){ 
  }
}

Может ли кто-нибудь направить меня в правильном направлении?

4 ответа

Решение

Это здесь:

while(!condition) {
  //perform calc
  return partialCalculationResult;
}

указывает на "дыру" в вашей логике. Это должно выглядеть так:

while(!condition) {
  // perform computation
  push intermediate results somewhere
}
return finalResult;

Другими словами: здесь вы говорите о двух разных элементах. Для этих "прогрессивных" обновлений вам понадобится какая-то общая структура данных; например Очередь.

Видите ли, в отличие от других языков, нет встроенной концепции "генератора", которая позволяла бы вам выводить значения из цикла; как вы можете сделать в Python или Scala, например.

Грязный вариант ставит System.out.println в то время как цикл.

Более чистым вариантом будет шаблон публикации / подписчика, например:

interface Subscriber {
    void onPartialResult(double partialResult);
}
class SystemOutSubscriber implements Subscriber{
    @Override
    void onPartialResult(double partialResult) {
        System.out.println(partialResult);
    }
}
class YourCalculatorClass {
    List<Subscriber> subscribers = ...
    public Object call() throws Exception {
       while(!condition) {
          //perform calc
          for(Subscriber s : subscribers) {
              s.onPartialResult(partialCalculationResult);
           }
        }
     }
}

Ниже приведен небольшой пример использования ExecutorServiceвыдвигать вызываемые задачи. Я помещаю их в цикл while для простоты примера, но они могут прийти откуда угодно. Сам вызываемый, конечно, использует самый глупый легкий пример, где он принимает число. Если число меньше 5, все хорошо, и мы возвращаем текст. Если нет, мы ничего не возвращаем. Когда будущее оценивается, а результат пуст, мы закрываем ExecutorService и называем его днем. Итак, это пример использования ExecutorService, Callable, а также Future сделать что-то похожее на то, что я мог бы понять из твоего объяснения.

public ExecutorServiceTest() {
    ExecutorService service = Executors.newCachedThreadPool();
    int num = 0;
    while (true) {
        Future<Optional<String>> future = service.submit(new MyCallable(num++));

        try {
            Optional<String> result = future.get();
            if (!result.isPresent()) {
                service.shutdown();
                break;
            }
            System.out.println(result.get());
        } catch (InterruptedException | ExecutionException e) {
            e.printStackTrace();
            service.shutdown();
        }
    }
}

private static class MyCallable implements Callable<Optional<String>> {
    private final int num;

    MyCallable(int num) {
        this.num = num;
    }

    @Override
    public Optional<String> call() throws Exception {
        if (num < 5)
            return Optional.of("My number is " + num);
        return Optional.empty();
    }
}

public static void main(String[] args) {

    new ExecutorServiceTest();
}

Вы можете использовать Thread.interrupt, чтобы остановить поток внутри цикла while и добавить оставшийся результат в список.

while(!condition){ list.add(addResultHere) Thread.interrupt(); }

Другие вопросы по тегам