使用CompletionService批处理任务

来源:互联网 发布:海量数据与数据港谁好 编辑:程序博客网 时间:2024/05/22 12:22
    
分享一篇关于Java中ExecutorService和CompletionService区别,有需要的朋友可以参考一下。

我们现在在Java中使用多线程通常不会直接用Thread对象了,而是会用到java.util.concurrent包下的ExecutorService类来初始化一个线程池供我们使用。

之前我一直习惯自己维护一个list保存submit的callable task所返回的Future对象。

在主线程中遍历这个list并调用Future的get()方法取到Task的返回值。

 

但是,我在很多地方会看到一些代码通过CompletionService包装ExecutorService,然后调用其take()方法去取Future对象。以前没研究过这两者之间的区别。

今天看了源代码之后就明白了。

 

这两者最主要的区别在于submit的task不一定是按照加入自己维护的list顺序完成的。

从list中遍历的每个Future对象并不一定处于完成状态,这时调用get()方法就会被阻塞住,如果系统是设计成每个线程完成后就能根据其结果继续做后面的事,这样对于处于list后面的但是先完成的线程就会增加了额外的等待时间。

而CompletionService的实现是维护一个保存Future对象的BlockingQueue。只有当这个Future对象状态是结束的时候,才会加入到这个Queue中,take()方法其实就是Producer-Consumer中的Consumer。它会从Queue中取出Future对象,如果Queue是空的,就会阻塞在那里,直到有完成的Future对象加入到Queue中。

所以,先完成的必定先被取出。这样就减少了不必要的等待时间。


import java.util.Random;  import java.util.concurrent.BlockingQueue;  import java.util.concurrent.Callable;  import java.util.concurrent.CompletionService;  import java.util.concurrent.ExecutionException;  import java.util.concurrent.ExecutorCompletionService;  import java.util.concurrent.ExecutorService;  import java.util.concurrent.Executors;  import java.util.concurrent.Future;  import java.util.concurrent.LinkedBlockingQueue;    public class Test17 {      public static void main(String[] args) throws Exception {          Test17 t = new Test17();          t.count1();          t.count2();      }  //使用阻塞容器保存每次Executor处理的结果,在后面进行统一处理      public void count1() throws Exception{          ExecutorService exec = Executors.newCachedThreadPool();          BlockingQueue<Future<Integer>> queue = new LinkedBlockingQueue<Future<Integer>>();          for(int i=0; i<10; i++){              Future<Integer> future =exec.submit(getTask());              queue.add(future);          }          int sum = 0;          int queueSize = queue.size();          for(int i=0; i<queueSize; i++){              sum += queue.take().get();          }          System.out.println("总数为:"+sum);          exec.shutdown();      }  //使用CompletionService(完成服务)保持Executor处理的结果      public void count2() throws InterruptedException, ExecutionException{          ExecutorService exec = Executors.newCachedThreadPool();          CompletionService<Integer> execcomp = new ExecutorCompletionService<Integer>(exec); // 线程池外面封装一层CompletionService         for(int i=0; i<10; i++){              execcomp.submit(getTask());          }          int sum = 0;          for(int i=0; i<10; i++){  //检索并移除表示下一个已完成任务的 Future,如果目前不存在这样的任务,则等待。              Future<Integer> future = execcomp.take();              sum += future.get();          }          System.out.println("总数为:"+sum);          exec.shutdown();      }      //得到一个任务      public Callable<Integer> getTask(){          final Random rand = new Random();          Callable<Integer> task = new Callable<Integer>(){              @Override              public Integer call() throws Exception {                  int i = rand.nextInt(10);                  int j = rand.nextInt(10);                  int sum = i*j;                  System.out.print(sum+"\t");                  return sum;              }          };          return task;      }      /**      * 执行结果:         6   6   14  40  40  0   4   7   0   0   总数为:106         12  6   12  54  81  18  14  35  45  35  总数为:312      */  }


0 0
原创粉丝点击