Search code examples
javamultithreadingjava.util.concurrent

Difference between Executor and ExecutorCompletionservice in java


As the question title itself says what is the difference between Executors and ExecutorCompletionService classes in java?

I am new to the Threading,so if any one can explain with a piece of code, that would help a lot.


Solution

  • Suppose you had a set of tasks A, B, C, D, E and you want to execute each of them asynchronously in an Executor and process the results 1 by 1 as they complete.

    With an Executor, you would do so like this:

    List<Future<?>> futures = new ArrayList<Future<?>>();
    futures.add(executorService.submit(A));
    futures.add(executorService.submit(B));
    futures.add(executorService.submit(C));
    futures.add(executorService.submit(D));
    futures.add(executorService.submit(E));
    
    //This loop must process the tasks in the order they were submitted: A, B, C, D, E
    for (Future<?> future:futures) {
        ? result = future.get();
        // Some processing here
    }
    

    The problem with this method is that there is no guarantee that task A will complete first. Thus, it is possible that the main thread will be blocking idly waiting for task A to complete when it could be processing the result of another task (say task B). Result processing latency could be reduced by using an ExecutorCompletionService.

    List<Future<?>> futures = new ArrayList<Future<?>>();
    futures.add(executorCompletionService.submit(A));
    futures.add(executorCompletionService.submit(B));
    futures.add(executorCompletionService.submit(C));
    futures.add(executorCompletionService.submit(D));
    futures.add(executorCompletionService.submit(E));
    
    //This for loop will process the tasks in the order they are completed,  
    //regardless of submission order
    for (int i=0; i<futures.size(); i++) {
        ? result = executorCompletionService.take().get();
        // Some processing here
    }
    

    So, in essence, ExecutorCompletionService could be used to squeeze out a little more efficiency when the order of processing task results does not matter.

    One important thing to note though. The implementation of ExecutorCompletionService contains a queue of results. If take or poll are not called to drain that queue, a memory leak will occur. Some people use the Future returned by submit to process results and this is NOT correct usage.