CompletionService的使用

CompletionService的介绍

CompletionService用于提交一组Callable任务,其take方法返回已完成的一个Callable任务对应的Future对象。
如果你向Executor提交了一个批处理任务,并且希望在它们完成后获得结果。为此你可以将每个任务的Future保存进一个集合,然后循环这个集合调用Future的get()取出数据。幸运的是CompletionService帮你做了这件事情。
CompletionService整合了Executor和BlockingQueue的功能。你可以将Callable任务提交给它去执行,然后使用类似于队列中的take和poll方法,在结果完整可用时获得这个结果,像一个打包的Future。
CompletionService的take返回的future是哪个先完成就先返回哪一个,而不是根据提交顺序。

CompletionService的使用

针对上面的需求“如果你向Executor提交了一个批处理任务,并且希望在它们完成后获得结果。”
可以有一下两种实现方式

方式一:自己维护一个Collection保存submit方法返回的Future存根,然后在主线程中遍历这个Collection并调用Future存根的get()方法取到线程的返回值。

方式一实现

 public class collection_future_Test {
   public static void main(String[] args){
         int taskSize = 10;
         ExecutorService executor = Executors.newFixedThreadPool(taskSize);
         List<Future<Integer>> futureList = new ArrayList<Future<Integer>>();
         
         for(int i= 1; i<=taskSize; i++){
             int sleep = taskSize -1;
             int value = i;
             //向线程池提交任务
             Future<Integer> future = executor.submit(new TestThread(sleep, value));
             //保留每个任务的Future
             futureList.add(future);
         }
         // 获取完成任务的返回结果
		 // 检查线程池任务执行结果
        for (int i = 1; i <=taskSize; i++) {
            try {
                    Future<Integer> future = futureList.get(i);
					System.out.println("result = "+result);
                 } catch (InterruptedException e) {
                     e.printStackTrace();
                 } catch (ExecutionException e) {
                     e.printStackTrace();
                 } 
        }

        // 关闭线程池
       // 所有任务已经完成,关闭线程池  
         System.out.println("all over ");
         executor.shutdown();
		         
     }
public class TestThread implements Callable<Integer> {

	 private int sleep;    
	    private int Value;
	    
	    public TestThread(int Seconds,int Value){
	        this.sleep = Seconds;
	        this.Value = Value;
	    }
	    

	    @Override
	    public Integer call() throws Exception {
	        System.out.println("begin to execute "+ Thread.currentThread().getName()); 
	        TimeUnit.SECONDS.sleep(sleep);
	        return Value;
	    }
}

这种方式的问题是:用所创建的集合来保存Future存根并循环调用其返回结果的时候,主线程并不能保证首先获得的是最先完成任务的线程返回值。它只是按加入线程池的顺序返回。因为take方法是阻塞方法,后面的任务完成了,前面的任务却没有完成,主程序就那样等待在那儿,只到前面的完成了,它才知道原来后面的也完成了

方式二:使用CompletionService类,它整合了Executor和BlockingQueue的功能。你可以将Callable任务提交给它去执行,然后使用类似于队列中的take方法获取线程的返回值。

方式二的实现:

public class CompletionServiceTest {
	public static void main(String[] args){
        int taskSize = 5;
        ExecutorService executor = Executors.newFixedThreadPool(taskSize);
        // 构建完成服务 
        CompletionService<Integer> completionService = new ExecutorCompletionService<Integer>(executor);
        
        for (int i=1;i<= taskSize; i++){
            // 睡眠时间 
            int sleep = taskSize - i;
            // 返回结果  
            int value = i;
            //向线程池提交任务
            completionService.submit(new TestThread(sleep, value));
            try {
                System.out.println("result:"+completionService.take().get());
            } catch (InterruptedException e) {
                e.printStackTrace();
            } catch (ExecutionException e) {
                e.printStackTrace();
            }
        }
        
        System.out.println("all over. ");
        executor.shutdown();
		}
	}
public class TestThread implements Callable<Integer> {

	 private int sleep;    
	    private int Value;
	    
	    public TestThread(int Seconds,int Value){
	        this.sleep = Seconds;
	        this.Value = Value;
	    }
	    

	    @Override
	    public Integer call() throws Exception {
	        System.out.println("begin to execute "+ Thread.currentThread().getName()); 
	        TimeUnit.SECONDS.sleep(sleep);
	        return Value;
	    }
}

总结

方法一,自己创建一个集合来保存Future存根并循环调用其返回结果的时候,主线程并不能保证首先获得的是最先完成任务的线程返回值。它只是按加入线程池的顺序返回。因为take方法是阻塞方法,后面的任务完成了,前面的任务却没有完成,主程序就那样等待在那儿,只到前面的完成了,它才知道原来后面的也完成了。

方法二,使用CompletionService来维护处理线程不的返回结果时,主线程总是能够拿到最先完成的任务的返回值,而不管它们加入线程池的顺序。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值