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

1. 使用并发容器将callable.call() 的返回Future存储起来。然后使用一个消费者线程去遍历这个并发容器,调用Future.isDone()去判断各个任务是否处理完毕。然后再处理响应的业务。

import java.util.concurrent.BlockingQueue;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.LinkedBlockingQueue; public class ExecutorResultManager { public static void main(String[] args) {
// 队列
BlockingQueue<Future<String>> futures = new LinkedBlockingQueue<>(); // 生产者
new Thread() {
@Override
public void run() {
ExecutorService pool = Executors.newCachedThreadPool(); for (int i=0; i< 10; i++) {
int index = i;
Future<String> submit = pool.submit(new Callable<String>() {
@Override
public String call() throws Exception {
return "task done" + index;
}
});
try {
futures.put(submit);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}.start(); // 消费者
new Thread() {
@Override
public void run() {
while(true) {
for (Future<String> future : futures) {
if(future.isDone()) {
// 处理业务
// ............. };
}
}
}
}.start();
} }

2. 使用jdk 自带线程池结果管理器:ExecutorCompletionService。它将BlockingQueue 和Executor 封装起来。然后使用ExecutorCompletionService.submit()方法提交任务。

submit 方法如下:

 public Future<V> submit(Callable<V> task) {
if (task == null) throw new NullPointerException(); // RunnableFuture封装了任务,使得任务既能run 也能get()
RunnableFuture<V> f = newTaskFor(task);
// 使用一个继承Runnable类的QueueingFutue 再次封装了我们的任务
executor.execute(new QueueingFuture(f));
return f;
}

我们再来看看QueueingFuture:

// 继承自FutureTask, FutureTask 也是一个Runnable的子类
private class QueueingFuture extends FutureTask<Void> {
QueueingFuture(RunnableFuture<V> task) {
super(task, null);
this.task = task;
}
// 实现了FutureTask 的done 方法,在任务处理完毕或者抛异常后将封装成Future的任务加入到队列。这样我们就能在队列中取到处处理完的任务,并通过Future.get()方法去取得处理完后的结果。不用自己去判断任务是否处理完毕了
protected void done() { completionQueue.add(task); }
private final Future<V> task;
}

简单实现:

import java.util.concurrent.Callable;
import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorCompletionService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future; public class ExecutorCompletionServiceManager { public static void main(String[] args) { ExecutorCompletionService<String> service = new ExecutorCompletionService<String>(
Executors.newCachedThreadPool()); // 生产者
new Thread() {
@Override
public void run() {
for (int i = 0; i < 10; i++) {
int index = i;
service.submit(new Callable<String>() {
@Override
public String call() throws Exception {
return "task done" + index;
}
});
}
}
}.start(); // 消费者
new Thread() {
@Override
public void run() {
try {
Future<String> take = service.take();
// do some thing........ } catch (InterruptedException e) {
e.printStackTrace();
}
}
}.start(); }
}

相对于原始的自造轮子处理方式,jdk 自带的工具类处理方式显得优雅了许多。

使用ExecutorCompletionService 管理线程池处理任务的返回结果的更多相关文章

  1. C# 多线程的自动管理(线程池) 基于Task的方式

    C# 多线程的自动管理(线程池) 在多线程的程序中,经常会出现两种情况:    1. 应用程序中线程把大部分的时间花费在等待状态,等待某个事件发生,然后给予响应.这一般使用 ThreadPool(线程 ...

  2. C#多线程学习(四) 多线程的自动管理(线程池)

    在多线程的程序中,经常会出现两种情况: 一种情况:   应用程序中,线程把大部分的时间花费在等待状态,等待某个事件发生,然后才能给予响应                   这一般使用ThreadPo ...

  3. Solr4.8.0源码分析(3)之index的线程池管理

    Solr4.8.0源码分析(3)之index的线程池管理 Solr建索引时候是有最大的线程数限制的,它由solrconfig.xml的<maxIndexingThreads>8</m ...

  4. Android 性能优化(16)线程优化:Creating a Manager for Multiple Threads 如何创建一个线程池管理类

    Creating a Manager for Multiple Threads 1.You should also read Processes and Threads The previous le ...

  5. Java之线程池管理

    JDK5后建议使用ExecutorService与Excutors来创建与管理线程池, 不再建议直接使用Thread. 开始不明白原因, 今天知道结果了:使用Thread.currnetThread. ...

  6. 深入Java线程管理(五):线程池

    这几天主要是狂看源程序,在弥补了一些以前知识空白的同时,也学会了不少新的知识(比如 NIO),或者称为新技术吧. 线程池就是其中之一,一提到线程,我们会想到以前<操作系统>的生产者与消费者 ...

  7. Java 并发:Executors 和线程池

    让我们开始来从入门了解一下 Java 的并发编程. 本文主要介绍如何开始创建线程以及管理线程池,在 Java 语言中,一个最简单的线程如下代码所示: Runnable runnable = new R ...

  8. Netty核心概念(7)之Java线程池

    1.前言 本章本来要讲解Netty的线程模型的,但是由于其是基于Java线程池设计而封装的,所以我们先详细学习一下Java中的线程池的设计.之前也说过Netty5被放弃的原因之一就是forkjoin结 ...

  9. Java 线程池(一):开篇及Executor整体框架介绍

    一.开篇 线程池.数据库连接池,在平时的学习中总能接触到这两个词,但它们到底是什么?和线程,数据库连接有什么关系?为什么需要“池”?“池”的概念及作用是什么?要弄清楚这些问题,就要深入到“池”的实现中 ...

随机推荐

  1. MySQL常用命令总结2

    USE db_name; //使用(打开)数据库 SELECT DATABASE(); //查看当前打开的数据库 CREATE TABLE tb_name( column_name data_type ...

  2. JavaScript基础教程

    功能介绍: (1)数据验证 弹出提示的对话框,产生判断的效果. (2)气泡提示窗口 右下角等等一类的窗口 (3)产生新窗口 (4)无边框窗口背景变灰,也是可以节约系统资源的

  3. access restriction

    一.既然存在访问规则,那么修改访问规则即可.打开项目的Build Path Configuration页面,打开报错的JAR包,选中Access rules条目,选择右侧的编辑按钮,添加一个访问规则即 ...

  4. 实例:SSH结合Easyui实现Datagrid的新增功能和Validatebox的验证功能

    在我前面一篇分页的基础上,新增了添加功能和添加过程中的Ajax与Validate的验证功能.其他的功能在后面的博客写来,如果对您有帮助,敬请关注. 先看一下实现的效果: (1)点击添加学生信息按键后跳 ...

  5. HDU 4287 Intelligent IME(字典树)

    在我没用hash之前,一直TLE,字符串处理时间过长,用了hash之后一直CE,(请看下图)我自从经历我的字典树G++MLE,C++AC以后,一直天真的用C++,后来的CE就是因为这个,G++才支持这 ...

  6. ajax编程**

    ajax 编程 *step1获得 XmlHttpRequest 对象.该对象由浏览器提供,但是该类型并没有标准化.ie 和其它浏览器不同,其它浏览器都支持该类型,而 ie 不支持. function ...

  7. PAT (Advanced Level) 1045. Favorite Color Stripe (30)

    最长公共子序列变形. #include<iostream> #include<cstring> #include<cmath> #include<algori ...

  8. Android4.4KitKat支持u盘功能

    Android4.4KitKat支持u盘功能 作者:  发布日期:2014-05-14 23:16:13 我来说两句(0) 0 Tag标签:功能   Android U 盘功能实现和分析 u 盘功能实 ...

  9. offsetTop、clientTop、scrollTop、offsetTop各属性介绍

    HTML精确定位:scrollLeft,scrollWidth,clientWidth,offsetWidth scrollHeight: 获取对象的滚动高度. scrollLeft:设置或获取位于对 ...

  10. CG中的数据变量类型

    CG 中的数据变量类型有三: float:高精度浮点值,通常是32位. half:中精度浮点值.通常是16位,范围是-60000至+60000,它适合存储UV坐标,颜色值等. fixed:低精度浮点值 ...