1

I need to provide code that using ExecutorService, Callable and Future will be doing some calculations and printing the partial results until defined condition is reached. First thing that comes to my mind is using while loop. Unfortunately as I understand ExecutorService.get() waits until the task is done, so I cannot do something like (pseudo code):

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

Could anyone guide me what's the proper direction I should go for?

GhostCat
  • 137,827
  • 25
  • 176
  • 248
cAMPy
  • 567
  • 2
  • 8
  • 25

4 Answers4

3

This here:

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

indicates a "hole" in your logic. This should probably go like this instead:

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

In other words: you are talking about two different elements here. For those "progress" updates you will need some kind of shared data structure; for example a Queue.

You see, in difference to other languages, there is no built-in "generator" concept that would allow you to yield values from a loop; like you can do in python or scala for example.

Community
  • 1
  • 1
GhostCat
  • 137,827
  • 25
  • 176
  • 248
1

The dirty option is putting a System.out.println within the while loop.

The cleaner option would be a publish/subscriber pattern, like:

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);
           }
        }
     }
}
Mario
  • 1,661
  • 13
  • 22
0

You can use Thread.interrupt to stop the thread inside while loop and add remaining result in list

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

saum22
  • 884
  • 12
  • 28
0

Below is a small example of using an ExecutorService to push callable tasks. I push them inside a while loop now for the ease of the example, but they can come from anywhere. The callable itself uses the most silly easy example of course where it takes in a number. If the number is below 5, all is good, and we return a text. If not, we return nothing. When the future is evaluated and the result is empty, we shut down the ExecutorService and call it a day. So, this is an example of using an ExecutorService, Callable, and Future to do something at least similar to what I could discern from your explanation.

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();
}
Terje
  • 1,753
  • 10
  • 13