When should I use a CompletionService over an ExecutorService?

后端 未结 10 2064
后悔当初
后悔当初 2020-11-28 01:52

I just found CompletionService in this blog post. However, this does\'t really showcases the advantages of CompletionService over a standard ExecutorService. The same code c

相关标签:
10条回答
  • 2020-11-28 02:38

    With ExecutorService, once you have submitted the tasks to run, you need to manually code for efficiently getting the results of the tasks completed.

    With CompletionService, this is pretty much automated. The difference is not very evident in the code you have presented because you are submitting just one task. However, imagine you have a list of tasks to be submitted. In the example below, multiple tasks are submitted to the CompletionService. Then, instead of trying to find out which task has completed (to get the results), it just asks the CompletionService instance to return the results as they become available.

    public class CompletionServiceTest {
    
            class CalcResult {
                 long result ;
    
                 CalcResult(long l) {
                     result = l;
                 }
            }
    
            class CallableTask implements Callable<CalcResult> {
                String taskName ;
                long  input1 ;
                int input2 ;
    
                CallableTask(String name , long v1 , int v2 ) {
                    taskName = name;
                    input1 = v1;
                    input2 = v2 ;
                }
    
                public CalcResult call() throws Exception {
                    System.out.println(" Task " + taskName + " Started -----");
                    for(int i=0;i<input2 ;i++) {
                        try {
                            Thread.sleep(200);
                        } catch (InterruptedException e) {
                            System.out.println(" Task " + taskName + " Interrupted !! ");
                            e.printStackTrace();
                        }
                        input1 += i;
                    }
                    System.out.println(" Task " + taskName + " Completed @@@@@@");
                    return new CalcResult(input1) ;
                }
    
            }
    
            public void test(){
                ExecutorService taskExecutor = Executors.newFixedThreadPool(3);
                CompletionService<CalcResult> taskCompletionService = new ExecutorCompletionService<CalcResult>(taskExecutor);
    
                int submittedTasks = 5;
                for (int i=0;i< submittedTasks;i++) {
                    taskCompletionService.submit(new CallableTask (
                            String.valueOf(i), 
                                (i * 10), 
                                ((i * 10) + 10  )
                            ));
                   System.out.println("Task " + String.valueOf(i) + "subitted");
                }
                for (int tasksHandled=0;tasksHandled<submittedTasks;tasksHandled++) {
                    try {
                        System.out.println("trying to take from Completion service");
                        Future<CalcResult> result = taskCompletionService.take();
                        System.out.println("result for a task availble in queue.Trying to get()");
                        // above call blocks till atleast one task is completed and results availble for it
                        // but we dont have to worry which one
    
                        // process the result here by doing result.get()
                        CalcResult l = result.get();
                        System.out.println("Task " + String.valueOf(tasksHandled) + "Completed - results obtained : " + String.valueOf(l.result));
    
                    } catch (InterruptedException e) {
                        // Something went wrong with a task submitted
                        System.out.println("Error Interrupted exception");
                        e.printStackTrace();
                    } catch (ExecutionException e) {
                        // Something went wrong with the result
                        e.printStackTrace();
                        System.out.println("Error get() threw exception");
                    }
                }
            }
        }
    
    0 讨论(0)
  • 2020-11-28 02:40

    Basically you use a CompletionService if you want to execute multiple tasks in parallel and then work with them in their completion order. So, if I execute 5 jobs, the CompletionService will give me the first one that that finishes. The example where there is only a single task confers no extra value over an Executor apart from the ability to submit a Callable.

    0 讨论(0)
  • 2020-11-28 02:41

    I think the javadoc best answers the question of when the CompletionService is useful in a way an ExecutorService isn't.

    A service that decouples the production of new asynchronous tasks from the consumption of the results of completed tasks.

    Basically, this interface allows a program to have producers which create and submit tasks (and even examine the results of those submissions) without knowing about any other consumers of the results of those tasks. Meanwhile, consumers which are aware of the CompletionService could poll for or take results without being aware of the producers submitting the tasks.

    For the record, and I could be wrong because it is rather late, but I am fairly certain that the sample code in that blog post causes a memory leak. Without an active consumer taking results out of the ExecutorCompletionService's internal queue, I'm not sure how the blogger expected that queue to drain.

    0 讨论(0)
  • 2020-11-28 02:44

    See it by yourself at run time,try to implement both solutions (Executorservice and Completionservice) and you'll see how different they behave and it will be more clear on when to use one or the other. There is an example here if you want http://rdafbn.blogspot.co.uk/2013/01/executorservice-vs-completionservice-vs.html

    0 讨论(0)
提交回复
热议问题