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.
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();
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With