通过CompletionService检查已取消的任务

时间:2015-12-01 18:22:03

标签: java java-8 future java.util.concurrent completion-service

我正在调查CompletionService类,我发现提交队列与completition队列的解耦非常有用。

但是我错过了一种方法来轮询/取消已取消的任务(可以认为这种方式已完成)。是否可以轻松完成?

Future<String> task1Future =  completionService.submit(myCallableTask1);
Future<String> task2Future =  completionService.submit(myCallableTask2);
task2Future.cancel();
Future<String> lastComplTaskFuture = completionService.take(); 
                        //Seems to return only the completed or 
                        //interrupted tasks, not those cancelled (task2)

编辑:在检查了一些答案后,我意识到发生了什么。 CompletitionService以与提交的作业相同的顺序返回。 如果你经营工作a,b和c;在工作时取消b和c;最后轮询completitionService,b和c的取消不会被通知,直到taks终止。 此外,我意识到如果您关闭执行程序而不是取消单个任务,那么仍然在队列中的那些任务不会达到completitionservice,即使它们的取消在活动任务尚未结束时完成。

EDIT2:好的,我添加了一个完整的测试用例

import java.util.concurrent.*;

public class CompletionTest {

    public static void main(String[] args){
        CompletionService<String> completion = 
                new ExecutorCompletionService<String>(Executors.newSingleThreadExecutor()); 
        Future<String> aFuture =
                 completion.submit(() -> {Thread.sleep(10000); return "A";});
        completion.submit(() -> {return "B";}).cancel(true);
        completion.submit(() -> {return "C";}).cancel(true);
        completion.submit(() -> {return "D";}).cancel(true);

        long arbitraryTime = System.currentTimeMillis();
        while (true){
            String result = getNextResult(completion);
            System.out.println(result);

            if (System.currentTimeMillis() > arbitraryTime+5000){
                aFuture.cancel(true);
            }
         }
    }

    public static String getNextResult(CompletionService<String> service){
        try {
            String taskId = service.take().get();
            return "'"+taskId+"' job completed successfully.";
        } 
        catch (InterruptedException e ) { return "Unknown job was interrupted/stopped while waiting (no thread.wait() or infinite loop in the job so I guess this should not be possible)."; } 
        catch (CancellationException e) { return "Unknown job was cancelled."; }  
        catch (ExecutionException e) { 
            return "Unknown job returned with the following internal exception while running: " + e.getCause().getMessage();
        }
    }
}

我期望输出如下:

Unknown job was cancelled.
Unknown job was cancelled.
Unknown job was cancelled.
'A' job completed successfully.

但它恰好是:

'A' job completed successfully.
Unknown job was cancelled.
Unknown job was cancelled.
Unknown job was cancelled.

我甚至尝试使用PriorityBlockingQueue作为CompletionService的队列,使用Comparator.<Future<String>,Boolean>comparing(Future::isCancelled).reversed(),但它既不起作用(我想如果元素改变状态,它也不会诉诸)

1 个答案:

答案 0 :(得分:1)

您正在使用单个线程向线程池提交任务。

您提交的第一个任务将使用该线程(短时间休眠)。

其他人将在ExecutorService内排队。取消相应的期货不会从该队列中删除相应的任务。它只是改变了Future的状态。

任务将保留在队列中,直到线程可以自由处理它们。线程将注意到相应的Future被取消并取消整个任务。当CompletionService知道他们已经完成&#34;时,就会发生这种情况。

考虑增加线程池的大小。