【问题标题】:CancellationException when using ExecutorService使用 ExecutorService 时的 CancellationException
【发布时间】:2023-03-29 08:53:01
【问题描述】:

我想等待两个任务完成然后返回它们的结果,但有时我会收到此错误。为什么? CancellationException 是从哪里来的?

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);          
    }
}

错误

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

【问题讨论】:

  • 第 43 行是哪一行?第 1 行是什么?您的堆栈跟踪显示第 1 行真的很奇怪。
  • 43 >>> if(future.get()) { 有什么问题?
  • 我猜您的一个可调用对象引发了异常。你能发布这些代码吗?

标签: java android multithreading


【解决方案1】:

您要求执行器服务以 5 秒的超时时间执行您的可调用对象。根据the javadoc

[在超时结束前]未完成的任务被取消

我的猜测是future.get() 会抛出一个CancellationException,因为已经到了超时并且执行器调用了future.cancel()

你可以:

  • 增加超时时间
  • 在您的可调用对象中捕获 InterruptedException 以优雅地处理取消操作

【讨论】:

  • 但是CancellationException 没有扩展InterruptedException 对吧?
  • 顺便说一句,我正在处理 InterruptedException 周围的 invokeAll 并且仍然得到 CancellationException
  • @LuísSoares 不,它没有。
  • @assylas:所以当你建议“抓住InterruptedException”时,你指的是每个get,而不是invokeAll,对吧?
  • @LuísSoares 不,我的意思是在调用方法中:如果调用future.cancel(),则会向正在执行的线程发送中断 - 在您的可调用对象中,您可以检查线程中断标志以查看它是否有被打断了。在问题中给出的示例中,尚不清楚是否可以这样做。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多