Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why Future isDone() block the program like Future get()?

I'm writing a program for generating fractal and fractal animation, the problem is on the animation...

I have a main thread that generate a List<Callable<Long>> tasks where each element has the information and resources for generate one frame; then i use an ExecutorService to submit the work.

The problem is in the impossibility to cancel these secondary thread if the user want to stop the calculus. Here is the code:

public class Animation extends Task<Long> {
protected Long call() throws Exception {
    long startTime = System.currentTimeMillis();

    WritableImage[] frames = new WritableImage[frameNumber];
    List<Callable<Long>> tasks = new ArrayList<>();

    updateProgress(count.incrementAndGet(), maxCount);
    if (isCancelled()) {
        return System.currentTimeMillis() - startTime;;
    }

    for (int k = 0; k < frameNumber; k++) {
        frames[k] = new WritableImage(
                (int) start.getCartesianPlane().getWidth(),
                (int) start.getCartesianPlane().getHeight());

        CartesianFractal tmp = FractalFactory.bulidFractal(
                selectedFractal, nextDataBox(k), colorPalette);

        tmp.setOnFinish(t -> {
            updateProgress(count.incrementAndGet(), maxCount);
            return null;
        });

        tasks.add((Callable<Long>) tmp);
        if (isCancelled()) {
            return System.currentTimeMillis() - startTime;;
        }
    }

    executor = Executors.newFixedThreadPool(4);
    updateProgress(count.incrementAndGet(), maxCount);
    if (isCancelled()) {
        return System.currentTimeMillis() - startTime;
    }
    try {
        result = executor.invokeAll(tasks);
    }
    catch (InterruptedException ex) {
        System.err.println(ex.toString());
    }

    // Check if all tasks are finished
    boolean finished = false;
    while (!finished) {
        finished = true;
        // Check if it is all done
        for (Future<Long> r : result) {
            finished = finished && r.isDone(); // THE PROGRAM BLOCKS HERE
            // Check if the task was cancelled
            if (isCancelled()) {
                // Cancell all task
                tasks.stream().forEach((t) -> {
                    ((CartesianFractal)t).myCancel();
                });
                // Turnoff the executor
                executor.shutdown();
                return System.currentTimeMillis() - startTime;
            }
        }
    }

    // Turnoff the executor
    executor.shutdown();
    updateProgress(count.incrementAndGet(), maxCount);

    makeAnimation();
    updateProgress(count.incrementAndGet(), maxCount);

    return System.currentTimeMillis() - startTime;
}
}

I really don't understood why Future.isDone() block the program like Future.get() !

This is my first question, so i hope it's all ok.

like image 268
Deglans Dalpasso Avatar asked Jan 23 '26 16:01

Deglans Dalpasso


1 Answers

I think that it might be easier if you implemented this using a CompletionService, which returns you Futures in the order that they complete.

For example:

Executor executor = Executors.newFixedThreadPool(4);

try {
    CompletionService completionService = new ExecutorCompletionService(executor);

    List<Future<Long>> futures = new ArrayList<>();
    for (Callable<Long> task : task) {
    futures.add(completionService.submit(task));
  }

  int pending = futures.size();
  while (pending > 0) {
      // Wait for up to 100ms to see if anything has completed.
      // The completed future is returned if one is found; otherwise null.
      // (Tune 100ms as desired)
      Future<Long> completed = completionService.poll(100, TimeUnit.MILLISECONDS);
      if (completed != null) {
          updateProgress(count.incrementAndGet(), maxCount);
          --pending;
    }
    if (isCancelled()) {
        // Cancel all task etc.
        break;
    }
  }
} finally {
    executor.shutdown();
}
like image 182
Andy Turner Avatar answered Jan 25 '26 05:01

Andy Turner



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!