java并发编程(二十一)-线程池CompletionService的使用(获取线程处理结果)

在我们日常使用线程池的时候,经常会有需要获得线程处理结果的时候。此时我们通常有两种做法。

《Java并发编程实践》一书6.3.5节CompletionService:Executor和BlockingQueue,有这样一段话:

  "如果向Executor提交了一组计算任务,并且希望在计算完成后获得结果,那么可以保留与每个任务关联的Future,然后反复使用get方法,同时将参数timeout指定为0,从而通过轮询来判断任务是否完成。这种方法虽然可行,但却有些繁琐。幸运的是,还有一种更好的方法:完成服务CompletionService。"

这里通过代码比较一下:

 

package com.caojiulu;

import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;

/**
 *@author caojilu 
 *
 *类说明:
 */
public class CompletionCase {
    private final int POOL_SIZE = Runtime.getRuntime().availableProcessors();
    private final int TOTAL_TASK = Runtime.getRuntime().availableProcessors();

    // 方法一,自己写集合来实现获取线程池中任务的返回结果
    public void testByQueue() throws Exception {
    	long start = System.currentTimeMillis();
    	//统计所有任务休眠的总时长
    	AtomicInteger count = new AtomicInteger(0);
        // 创建线程池
        ExecutorService pool = Executors.newFixedThreadPool(POOL_SIZE);
        //容器存放提交给线程池的任务,list,map,
        BlockingQueue> queue = 
        		new LinkedBlockingQueue>();

        // 向里面扔任务
        for (int i = 0; i < TOTAL_TASK; i++) {
            Future future = pool.submit(new WorkTask("ExecTask" + i));
            queue.add(future);//i=0 先进队列,i=1的任务跟着进
        }

        // 检查线程池任务执行结果
        for (int i = 0; i < TOTAL_TASK; i++) {
        	int sleptTime = queue.take().get();///i=0先取到,i=1的后取到
        	System.out.println(" slept "+sleptTime+" ms ...");        	
        	count.addAndGet(sleptTime);
        }

        // 关闭线程池
        pool.shutdown();
        System.out.println("-------------tasks sleep time "+count.get()
        		+"ms,and spend time "
        		+(System.currentTimeMillis()-start)+" ms");
    }

    // 方法二,通过CompletionService来实现获取线程池中任务的返回结果
    public void testByCompletion() throws Exception {
    	long start = System.currentTimeMillis();
    	AtomicInteger count = new AtomicInteger(0);
        // 创建线程池
        ExecutorService pool = Executors.newFixedThreadPool(POOL_SIZE);
        CompletionService cService = new ExecutorCompletionService<>(pool);
        
        // 向里面扔任务
        for (int i = 0; i < TOTAL_TASK; i++) {
        	cService.submit(new WorkTask("ExecTask" + i));
        }
        
        // 检查线程池任务执行结果
        for (int i = 0; i < TOTAL_TASK; i++) {
        	int sleptTime = cService.take().get();
        	System.out.println(" slept "+sleptTime+" ms ...");        	
        	count.addAndGet(sleptTime);
        }        

        // 关闭线程池
        pool.shutdown();
        System.out.println("-------------tasks sleep time "+count.get()
			+"ms,and spend time "
			+(System.currentTimeMillis()-start)+" ms");
    }

    public static void main(String[] args) throws Exception {
        CompletionCase t = new CompletionCase();
        t.testByQueue();
        t.testByCompletion();
    }
}

运行结果比较:

 slept 541 ms ...
 slept 883 ms ...
 slept 890 ms ...
 slept 436 ms ...
-------------tasks sleep time 2750ms,and spend time 902 ms
 slept 81 ms ...
 slept 294 ms ...
 slept 364 ms ...
 slept 374 ms ...
-------------tasks sleep time 1113ms,and spend time 376 ms
 


可以明显的看到,CompletionService要快很多。

所以如果需要通过线程池获取线程的返回结果时,请使用ExecutorCompletionService

 

你可能感兴趣的:(多线程,并发编程)