When should I use a CompletionService over an ExecutorService?

后端 未结 10 2063
后悔当初
后悔当初 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:20

    If the task producer is not interested in the results and it is another component's responsibility to process results of asynchronous task executed by executor service, then you should use CompletionService. It helps you in separating task result processor from task producer. See example http://www.zoftino.com/java-concurrency-executors-framework-tutorial

    0 讨论(0)
  • 2020-11-28 02:32
    package com.barcap.test.test00;
    
    import java.util.concurrent.*;
    
    /**
     * Created by Sony on 25-04-2019.
     */
    public class ExecutorCompletest00 {
    
        public static void main(String[] args) {
    
            ExecutorService exc= Executors.newFixedThreadPool( 10 );
            ExecutorCompletionService executorCompletionService= new ExecutorCompletionService( exc );
    
            for (int i=1;i<10;i++){
                Task00 task00= new Task00( i );
                executorCompletionService.submit( task00 );
            }
            for (int i=1;i<20;i++){
                try {
                    Future<Integer> future= (Future <Integer>) executorCompletionService.take();
                    Integer inttest=future.get();
                    System.out.println(" the result of completion service is "+inttest);
    
                   break;
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } catch (ExecutionException e) {
                    e.printStackTrace();
                }
            }
        }
    }
    

    =======================================================

    package com.barcap.test.test00;
    
    import java.util.*;
    import java.util.concurrent.*;
    
    /**
     * Created by Sony on 25-04-2019.
     */
    public class ExecutorServ00 {
    
        public static void main(String[] args) {
            ExecutorService executorService=Executors.newFixedThreadPool( 9 );
            List<Future> futList= new ArrayList <>(  );
            for (int i=1;i<10;i++) {
               Future result= executorService.submit( new Task00( i ) );
               futList.add( result );
            }
    
             for (Future<Integer> futureEach :futList ){
                 try {
                  Integer inm=   futureEach.get();
    
                     System.out.println("the result of future executorservice is "+inm);
                     break;
                 } catch (InterruptedException e) {
                     e.printStackTrace();
                 } catch (ExecutionException e) {
                     e.printStackTrace();
                 }
             }
        }
    }
    

    ===========================================================

    package com.barcap.test.test00;
    
    import java.util.concurrent.*;
    
    /**
     * Created by Sony on 25-04-2019.
     */
    public class Task00 implements Callable<Integer> {
    
        int i;
    
        public Task00(int i) {
            this.i = i;
        }
    
        @Override
        public Integer call() throws Exception {
            System.out.println(" the current thread is "+Thread.currentThread().getName()  +" the result should be "+i);
            int sleepforsec=100000/i;
             Thread.sleep( sleepforsec );
            System.out.println(" the task complted for "+Thread.currentThread().getName()  +" the result should be "+i);
    
    
    
            return i;
        }
    }
    

    ======================================================================

    difference of logs for executor completion service: the current thread is pool-1-thread-1 the result should be 1 the current thread is pool-1-thread-2 the result should be 2 the current thread is pool-1-thread-3 the result should be 3 the current thread is pool-1-thread-4 the result should be 4 the current thread is pool-1-thread-6 the result should be 6 the current thread is pool-1-thread-5 the result should be 5 the current thread is pool-1-thread-7 the result should be 7 the current thread is pool-1-thread-9 the result should be 9 the current thread is pool-1-thread-8 the result should be 8 the task complted for pool-1-thread-9 the result should be 9 teh result is 9 the task complted for pool-1-thread-8 the result should be 8 the task complted for pool-1-thread-7 the result should be 7 the task complted for pool-1-thread-6 the result should be 6 the task complted for pool-1-thread-5 the result should be 5 the task complted for pool-1-thread-4 the result should be 4 the task complted for pool-1-thread-3 the result should be 3

    the task complted for pool-1-thread-2 the result should be 2

    the current thread is pool-1-thread-1 the result should be 1 the current thread is pool-1-thread-3 the result should be 3 the current thread is pool-1-thread-2 the result should be 2 the current thread is pool-1-thread-5 the result should be 5 the current thread is pool-1-thread-4 the result should be 4 the current thread is pool-1-thread-6 the result should be 6 the current thread is pool-1-thread-7 the result should be 7 the current thread is pool-1-thread-8 the result should be 8 the current thread is pool-1-thread-9 the result should be 9 the task complted for pool-1-thread-9 the result should be 9 the task complted for pool-1-thread-8 the result should be 8 the task complted for pool-1-thread-7 the result should be 7 the task complted for pool-1-thread-6 the result should be 6 the task complted for pool-1-thread-5 the result should be 5 the task complted for pool-1-thread-4 the result should be 4 the task complted for pool-1-thread-3 the result should be 3 the task complted for pool-1-thread-2 the result should be 2 the task complted for pool-1-thread-1 the result should be 1 the result of future is 1

    =======================================================

    for executorservice the result will only be avialable after all tasks complted.

    executor completionservice any result avilable make that return.

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

    First of all, if we do not want to waste processor time, we will not use

    while (!future.isDone()) {
            // Do some work...
    }
    

    We must use

    service.shutdown();
    service.awaitTermination(14, TimeUnit.DAYS);
    

    The bad thing about this code is that it will shut down ExecutorService. If we want to continue work with it (i.e. we have some recursicve task creation), we have two alternatives: invokeAll or ExecutorService.

    invokeAll will wait untill all tasks will be complete. ExecutorService grants us ability to take or poll results one by one.

    And, finily, recursive example:

    ExecutorService executorService = Executors.newFixedThreadPool(THREAD_NUMBER);
    ExecutorCompletionService<String> completionService = new ExecutorCompletionService<String>(executorService);
    
    while (Tasks.size() > 0) {
        for (final Task task : Tasks) {
            completionService.submit(new Callable<String>() {   
                @Override
                public String call() throws Exception {
                    return DoTask(task);
                }
            });
        } 
    
        try {                   
            int taskNum = Tasks.size();
            Tasks.clear();
            for (int i = 0; i < taskNum; ++i) {
                Result result = completionService.take().get();
                if (result != null)
                    Tasks.add(result.toTask());
            }           
        } catch (InterruptedException e) {
        //  error :(
        } catch (ExecutionException e) {
        //  error :(
        }
    }
    
    0 讨论(0)
  • 2020-11-28 02:36

    there is another advantage of using completionservice: Performance

    when you call future.get(), you are spin waiting:

    from java.util.concurrent.CompletableFuture

      private Object waitingGet(boolean interruptible) {
            Signaller q = null;
            boolean queued = false;
            int spins = -1;
            Object r;
            while ((r = result) == null) {
                if (spins < 0)
                    spins = (Runtime.getRuntime().availableProcessors() > 1) ?
                        1 << 8 : 0; // Use brief spin-wait on multiprocessors
                else if (spins > 0) {
                    if (ThreadLocalRandom.nextSecondarySeed() >= 0)
                        --spins;
                }
    

    when you have a long-running task, this will be a disaster for performance.

    with completionservice, once the task is done, it's result will be enqueued and you can poll the queue with lower performance overhand.

    completionservice achieve this by using wrap task with a done hook.

    java.util.concurrent.ExecutorCompletionService

        private class QueueingFuture extends FutureTask<Void> {
        QueueingFuture(RunnableFuture<V> task) {
            super(task, null);
            this.task = task;
        }
        protected void done() { completionQueue.add(task); }
        private final Future<V> task;
    }
    
    0 讨论(0)
  • 2020-11-28 02:37

    Omitting many details:

    • ExecutorService = incoming queue + worker threads
    • CompletionService = incoming queue + worker threads + output queue
    0 讨论(0)
  • 2020-11-28 02:37

    Let's say you have 5 long running task(callable task) and you have submitted those task to executer service. Now imagine you don't want to wait for all 5 task to compete instead you want to do some sort of processing on these task if any one completes. Now this can be done either by writing polling logic on future objects or use this API.

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