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

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. UVALive 4992 Jungle Outpost(半平面交)

    题意:给你n个塔(点)形成一个顺时针的凸包,敌人可以摧毁任何塔,摧毁后剩下的塔再组成凸包 在开始的凸包内选一点为主塔,保证敌人摧毁尽量多塔时主塔都还在现在的凸包内,求出最多摧毁的塔 题解:这题关键就是 ...

  2. 【spring boot】SpringBoot初学(2) - properties配置和读取

    前言 只是简单的properties配置学习,修改部分"约定"改为自定义"配置".真正使用和遇到问题是在细看. 一.主要 核心只是demo中的: @Proper ...

  3. L10,not for jazz

    expressions: It is called a clavichord这被称为古钢琴 a friend of my father's我父亲的朋友   words: musical,adj,音乐的 ...

  4. Android Studio 提示Error running app: No Android facet found for app

    错误解决办法如下: 可以通过以下几个步骤解决该问题: 1) 点击菜单File -> 选择Project Structure, 或使用快捷键 (Ctrl+Alt+Shift+S) 打开”Proje ...

  5. 用MyEclipse自动生成hibernate映射文件和实体类

    创建数据库,创建相应的表 点击图标,选择MyEclipse Datebase Explorer 右击空白区域,选择new菜单,根据提示创建数据库连接,创建好后会显示你所创建的连接名,如图mysqldb ...

  6. oracle中的赋权

    1 怎么给用户赋权限 grant create view to scott; (create view 是权限的名称) 2 怎么给用户撤销权限 revoke create view from scot ...

  7. hibernate里的generator中class =value介绍

    在*.hbm.xml必须声明的<generator>子元素是一个Java类的名字,用来为该持久化类的实例生成唯一的标识.<generator class="sequence ...

  8. angular Jsonp的坑

    angular 为了解决跨域问题 一些第三方接口会提供jsonp来调用,需要使用callback=JSON_CALLBACK来处理 这个时候问题来了,有些借口是不支持callback里面带有点语法的, ...

  9. sockaddr结构体

    sockaddr 本词条缺少名片图,补充相关内容使词条更完整,还能快速升级,赶紧来编辑吧! 一,用于存储参与(IP)Windows套接字通信的计算机上的一个internet协议(IP)地址.为了统一地 ...

  10. HDU 2444 The Accomodation of Students(二分图判定+最大匹配)

    这是一个基础的二分图,题意比较好理解,给出n个人,其中有m对互不了解的人,先让我们判断能不能把这n对分成两部分,这就用到的二分图的判断方法了,二分图是没有由奇数条边构成环的图,这里用bfs染色法就可以 ...