Вызывается с помощью цикла 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(); }