I want to wait two tasks to finish then return the result of them but sometimes I get this error. Why? Where did CancellationException come from?
public class ShouldVoteTask extends AbstractWorkerTask<Void, Void, Boolean> {
private final int placeID;
private final int userID;
public ShouldVoteTask(final int placeID, final int userID) {
this.placeID = placeID;
this.userID = userID;
}
@Override
protected Boolean doInBackground(final Void... params) {
try {
// Prepare callables.
final IsMaxRatingCallable call1 = new IsMaxRatingCallable(placeID);
final DidVoteCallable call2 = new DidVoteCallable(placeID, userID);
final List<Callable<Boolean>> callables = new ArrayList<Callable<Boolean>>();
callables.add(call1);
callables.add(call2);
// Execute them.
final ExecutorService service = Executors.newFixedThreadPool(2);
final List<Future<Boolean>> futures = service.invokeAll(callables, 5, TimeUnit.SECONDS);
// Check the result.
boolean result = true;
for(final Future<Boolean> future : futures) {
if(future.get()) {
result = false;
}
}
return result;
} catch (final InterruptedException e) {
e.printStackTrace();
} catch (final ExecutionException e) {
e.printStackTrace();
}
return false;
}
}
private class IsMaxRatingCallable implements Callable<Boolean> {
private final int placeID;
public IsMaxRatingCallable(final int placeID) {
this.placeID = placeID;
}
@Override
public Boolean call() throws Exception {
return Places.isMaxRating(placeID);
}
}
private class DidVoteCallable implements Callable<Boolean> {
private final int placeID;
private final int userID;
public DidVoteCallable(final int placeID, final int userID) {
this.placeID = placeID;
this.userID = userID;
}
@Override
public Boolean call() throws Exception {
return Votes.didVote(placeID, userID);
}
}
Error
E/AndroidRuntime(19014): FATAL EXCEPTION: AsyncTask #1
E/AndroidRuntime(19014): java.lang.RuntimeException: An error occured while executing doInBackground()
E/AndroidRuntime(19014): at android.os.AsyncTask$3.done(AsyncTask.java:200)
E/AndroidRuntime(19014): at java.util.concurrent.FutureTask$Sync.innerSetException(FutureTask.java:274)
E/AndroidRuntime(19014): at java.util.concurrent.FutureTask.setException(FutureTask.java:125)
E/AndroidRuntime(19014): at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:308)
E/AndroidRuntime(19014): at java.util.concurrent.FutureTask.run(FutureTask.java:138)
E/AndroidRuntime(19014): at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1088)
E/AndroidRuntime(19014): at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:581)
E/AndroidRuntime(19014): at java.lang.Thread.run(Thread.java:1027)
E/AndroidRuntime(19014): Caused by: java.util.concurrent.CancellationException
E/AndroidRuntime(19014): at java.util.concurrent.FutureTask$Sync.innerGet(FutureTask.java:222)
E/AndroidRuntime(19014): at java.util.concurrent.FutureTask.get(FutureTask.java:83)
E/AndroidRuntime(19014): at com.vfa.android.planet.task.ShouldVoteTask.doInBackground(ShouldVoteTask.java:43)
E/AndroidRuntime(19014): at com.vfa.android.planet.task.ShouldVoteTask.doInBackground(ShouldVoteTask.java:1)
E/AndroidRuntime(19014): at android.os.AsyncTask$2.call(AsyncTask.java:185)
E/AndroidRuntime(19014): at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:306)
E/AndroidRuntime(19014): ... 4 more
ExecutorService is the central mechanism to execute tasks in Java. When we run our tasks in a thread pool backed by an ExecutorService, we must pay attention to exception handling.
Shutting Down an ExecutorService In general, the ExecutorService will not be automatically destroyed when there is no task to process. It will stay alive and wait for new work to do. In some cases this is very helpful, such as when an app needs to process tasks that appear on an irregular basis or the task quantity is not known at compile time.
The easiest way to create ExecutorService is to use one of the factory methods of the Executors class. For example, the following line of code will create a thread pool with 10 threads:
The ScheduledExecutorService runs tasks after some predefined delay and/or periodically. Once again, the best way to instantiate a ScheduledExecutorService is to use the factory methods of the Executors class. For this section, we use a ScheduledExecutorService with one thread:
You ask your executor service to execute your callables with a timeout of 5 seconds. According to the javadoc:
tasks that have not completed [by the end of the timeout] are cancelled
My guess is that future.get()
throws a CancellationException
because the timeout has been reached and the executor calls future.cancel()
.
You could either:
InterruptedException
in your callable to handle the cancellation gracefullyIf 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