CompletionService用于提交一组Callable任务,其take方法返回已完成的一个Callable任务对应的Future对象。
如果你向Executor提交了一个批处理任务,并且希望在它们完成后获得结果。为此你可以将每个任务的Future保存进一个集合,然后循环这个集合调用Future的get()取出数据。幸运的是CompletionService帮你做了这件事情。
CompletionService整合了Executor和BlockingQueue的功能。你可以将Callable任务提交给它去执行,然后使用类似于队列中的take和poll方法,在结果完整可用时获得这个结果,像一个打包的Future。
CompletionService的take返回的future是哪个先完成就先返回哪一个,而不是根据提交顺序。
例子:
1 import java.util.Random;
2 import java.util.concurrent.Callable;
3 import java.util.concurrent.CompletionService;
4 import java.util.concurrent.ExecutionException;
5 import java.util.concurrent.ExecutorCompletionService;
6 import java.util.concurrent.ExecutorService;
7 import java.util.concurrent.Executors;
8
9 public class CallableAndFuture {
10
11 public static void main(String[] args) {
12 ExecutorService threadPool = Executors. newFixedThreadPool(10);
13 CompletionService<Integer> completionService = new ExecutorCompletionService<Integer>(threadPool);
14
15 for (int i = 0; i < 10; i++) {
16 final int seq = i;
17 System. out.println("开始提交第" + seq + "个任务");
18 completionService.submit( new Callable<Integer>() {
19
20 @Override
21 public Integer call() throws Exception {
22 Thread. sleep(new Random().nextInt(5000));
23 return seq;
24 }
25 });
26 }
27
28 for (int i = 0; i < 10; i++) {
29 try {
30 // 取出并移除表示下一个已完成任务的 Future,如果目前不存在这样的任务,则等待。
31 Integer seq = completionService.take().get();
32 System. out.println("第" + seq + "个任务返回");
33 } catch (InterruptedException e) {
34 e.printStackTrace();
35 } catch (ExecutionException e) {
36 e.printStackTrace();
37 }
38 }
39 }
40
41 }
麦田实战
1.线程池构造
/**
* 构造请求线程池,队列大小为1000
*/
private ExecutorService executorService = new ThreadPoolExecutor(CORE_POOL_SIZE, MAXIMUM_POOL_SIZE,
KEEP_ALIVE_TIME, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>(capacity), new ThreadFactory() {
AtomicInteger poolNumber = new AtomicInteger(1);
AtomicInteger threadNumber = new AtomicInteger(1);
@Override
public Thread newThread(Runnable r) {
String namePrefix = String.format("reportPool-%s-thread-", poolNumber.getAndIncrement());
return new Thread(r, namePrefix + threadNumber.getAndIncrement());
}
});
2.并发请求
/**
* 异步并发请求多个存储过程
*/
protected Map<String, List<Map<String, Object>>> buildAsyncProcRequest(List<String> procedureList,
final List<String> params) {
ExecutorCompletionService<Map<String, List<Map<String, Object>>>> completionService =
new ExecutorCompletionService(executorService);
for (final String procedureName : procedureList) {
completionService.submit(new Callable<Map<String, List<Map<String, Object>>>>() {
@Override
public Map<String, List<Map<String, Object>>> call() throws Exception {
List<Map<String, Object>> resultSet = getResultSet(procedureName, params);
Map<String, List<Map<String, Object>>> result = Maps.newHashMap();
result.put(procedureName, resultSet);
return result;
}
});
}
return getResultMap(completionService, procedureList);
}
3.处理结果
/**
* 获取异步请求结果
*
* @param completionService service
* @param procedureList procedure names list
* @return 结果MAP
*/
private Map<String, List<Map<String, Object>>> getResultMap(CompletionService<Map<String, List<Map<String, Object>>>>
completionService, List<String> procedureList) {
Map<String, List<Map<String, Object>>> resultMap = null;
for (String procedureName : procedureList) {
try {
Future<Map<String, List<Map<String, Object>>>> future = completionService.take();
if (resultMap == null) {
resultMap = future.get(5, TimeUnit.SECONDS);
} else {
for (Entry<String, List<Map<String, Object>>> stringListEntry : future.get(5, TimeUnit.SECONDS).entrySet()) {
resultMap.put(stringListEntry.getKey(), stringListEntry.getValue());
}
}
} catch (InterruptedException e) {
throw new AppSysException(String
.format("process procedure:%s returned result interrupted,exception:%s", procedureName, e.getMessage()));
} catch (ExecutionException e) {
throw new AppSysException(
String.format("procedure:%s result execute error,exception:%s", procedureName, e.getMessage()));
} catch (TimeoutException e) {
throw new AppSysException(
String.format("fetch procedure:%s result timeout,exception:%s", procedureName, e.getMessage()));
}
}
return resultMap;
}