Executor框架是指java 5中引入的一系列并发库中与executor相关的一些功能类,其中包括线程池,Executor,Executors,ExecutorService,CompletionService,Future,Callable等。他们的关系为:

并发编程的一种编程方式是把任务拆分为一些列的小任务,即Runnable,然后在提交给一个Executor执行,Executor.execute(Runnalbe) 。Executor在执行时使用内部的线程池完成操作。

一、创建线程池

Executors类,提供了一系列工厂方法用于创先线程池,返回的线程池都实现了ExecutorService接口。

public static ExecutorService newFixedThreadPool(int nThreads)

创建固定数目线程的线程池。

public static ExecutorService newCachedThreadPool()

创建一个可缓存的线程池,调用execute 将重用以前构造的线程(如果线程可用)。如果现有线程没有可用的,则创建一个新线程并添加到池中。终止并从缓存中移除那些已有 60 秒钟未被使用的线程。

public static ExecutorService newSingleThreadExecutor()

创建一个单线程化的Executor。

public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize)

创建一个支持定时及周期性的任务执行的线程池,多数情况下可用来替代Timer类

Executor executor = Executors.newFixedThreadPool(10);
Runnable task = new Runnable() {
@Override
public void run() {
System.out.println("task over");
}
};
executor.execute(task); executor = Executors.newScheduledThreadPool(10);
ScheduledExecutorService scheduler = (ScheduledExecutorService) executor;
scheduler.scheduleAtFixedRate(task, 10, 10, TimeUnit.SECONDS);

二、ExecutorService与生命周期

ExecutorService扩展了Executor并添加了一些生命周期管理的方法。一个Executor的生命周期有三种状态,运行 ,关闭 ,终止。Executor创建时处于运行状态。当调用ExecutorService.shutdown()后,处于关闭状态,isShutdown()方法返回true。这时,不应该再想Executor中添加任务,所有已添加的任务执行完毕后,Executor处于终止状态,isTerminated()返回true。

如果Executor处于关闭状态,往Executor提交任务会抛出unchecked exception RejectedExecutionException。

三、使用Callable,Future返回结果

Future<V>代表一个异步执行的操作,通过get()方法可以获得操作的结果,如果异步操作还没有完成,则,get()会使当前线程阻塞。FutureTask<V>实现了Future<V>和Runable<V>。Callable代表一个有返回值得操作。

Callable<Integer> func = new Callable<Integer>(){
public Integer call() throws Exception {
System.out.println("inside callable");
Thread.sleep(1000);
return new Integer(8);
}
};
FutureTask<Integer> futureTask = new FutureTask<Integer>(func);
Thread newThread = new Thread(futureTask);
newThread.start(); try {
System.out.println("blocking here");
Integer result = futureTask.get();
System.out.println(result);
} catch (InterruptedException ignored) {
} catch (ExecutionException ignored) {
}

ExecutoreService提供了submit()方法,传递一个Callable,或Runnable,返回Future。如果Executor后台线程池还没有完成Callable的计算,这调用返回Future对象的get()方法,会阻塞直到计算完成。

例子:并行计算数组的和。

package executorservice;  

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.FutureTask; public class ConcurrentCalculator { private ExecutorService exec;
private int cpuCoreNumber;
private List<Future<Long>> tasks = new ArrayList<Future<Long>>(); // 内部类
class SumCalculator implements Callable<Long> {
private int[] numbers;
private int start;
private int end; public SumCalculator(final int[] numbers, int start, int end) {
this.numbers = numbers;
this.start = start;
this.end = end;
} public Long call() throws Exception {
Long sum = 0l;
for (int i = start; i < end; i++) {
sum += numbers[i];
}
return sum;
}
} public ConcurrentCalculator() {
cpuCoreNumber = Runtime.getRuntime().availableProcessors();
exec = Executors.newFixedThreadPool(cpuCoreNumber);
} public Long sum(final int[] numbers) {
// 根据CPU核心个数拆分任务,创建FutureTask并提交到Executor
for (int i = 0; i < cpuCoreNumber; i++) {
int increment = numbers.length / cpuCoreNumber + 1;
int start = increment * i;
int end = increment * i + increment;
if (end > numbers.length)
end = numbers.length;
SumCalculator subCalc = new SumCalculator(numbers, start, end);
FutureTask<Long> task = new FutureTask<Long>(subCalc);
tasks.add(task);
if (!exec.isShutdown()) {
exec.submit(task);
}
}
return getResult();
} /**
* 迭代每个只任务,获得部分和,相加返回
*
* @return
*/
public Long getResult() {
Long result = 0l;
for (Future<Long> task : tasks) {
try {
// 如果计算未完成则阻塞
Long subSum = task.get();
result += subSum;
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
return result;
} public void close() {
exec.shutdown();
}
} //main
int[] numbers = new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 10, 11 };
ConcurrentCalculator calc = new ConcurrentCalculator();
Long sum = calc.sum(numbers);
System.out.println(sum);
calc.close();

四、CompletionService

在刚在的例子中,getResult()方法的实现过程中,迭代了FutureTask的数组,如果任务还没有完成则当前线程会阻塞,如果我们希望任意字任务完成后就把其结果加到result中,而不用依次等待每个任务完成,可以使CompletionService。生产者submit()执行的任务。使用者take()已完成的任务,并按照完成这些任务的顺序处理它们的结果 。也就是调用CompletionService的take方法是,会返回按完成顺序放回任务的结果,CompletionService内部维护了一个阻塞队列BlockingQueue,如果没有任务完成,take()方法也会阻塞。修改刚才的例子使用CompletionService:

public class ConcurrentCalculator2 {  

    private ExecutorService exec;
private CompletionService<Long> completionService; private int cpuCoreNumber; // 内部类
class SumCalculator implements Callable<Long> {
......
} public ConcurrentCalculator2() {
cpuCoreNumber = Runtime.getRuntime().availableProcessors();
exec = Executors.newFixedThreadPool(cpuCoreNumber);
completionService = new ExecutorCompletionService<Long>(exec); } public Long sum(final int[] numbers) {
// 根据CPU核心个数拆分任务,创建FutureTask并提交到Executor
for (int i = 0; i < cpuCoreNumber; i++) {
int increment = numbers.length / cpuCoreNumber + 1;
int start = increment * i;
int end = increment * i + increment;
if (end > numbers.length)
end = numbers.length;
SumCalculator subCalc = new SumCalculator(numbers, start, end);
if (!exec.isShutdown()) {
completionService.submit(subCalc); } }
return getResult();
} /**
* 迭代每个只任务,获得部分和,相加返回
*
* @return
*/
public Long getResult() {
Long result = 0l;
for (int i = 0; i < cpuCoreNumber; i++) {
try {
Long subSum = completionService.take().get();
result += subSum;
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
return result;
} public void close() {
exec.shutdown();
}
}

Executor框架(转载)的更多相关文章

  1. Java并发—线程池框架Executor总结(转载)

    为什么引入Executor线程池框架 new Thread()的缺点 每次new Thread()耗费性能 调用new Thread()创建的线程缺乏管理,被称为野线程,而且可以无限制创建,之间相互竞 ...

  2. JAVA 1.5 并发之 Executor框架 (内容为转载)

    本文内容转自 http://www.iteye.com/topic/366591 Executor框架是指java 5中引入的一系列并发库中与executor相关的一些功能类,其中包括线程池,Exec ...

  3. java并发编程(十七)Executor框架和线程池

    转载请注明出处:http://blog.csdn.net/ns_code/article/details/17465497   Executor框架简介 在Java 5之后,并发编程引入了一堆新的启动 ...

  4. Java基础系列--Executor框架(一)

    文章来源:http://www.cnblogs.com/V1haoge/p/8393618.html 一.Executor框架介绍 Executor框架是JDK1.5之后出现的,位于juc包中,是并发 ...

  5. 【Java并发编程】:并发新特性—Executor框架与线程池

    Executor框架简介 在Java5之后,并发编程引入了一堆新的启动.调度和管理线程的API.Executor框架便是Java 5中引入的,其内部使用了线程池机制,它在java.util.cocur ...

  6. Java并发和多线程(二)Executor框架

    Executor框架 1.Task?Thread? 很多人在学习多线程这部分知识的时候,容易搞混两个概念:任务(task)和线程(thread). 并发编程可以使我们的程序可以划分为多个分离的.独立运 ...

  7. java并发编程-Executor框架

    Executor框架是指java 5中引入的一系列并发库中与executor相关的一些功能类,其中包括线程池,Executor,Executors,ExecutorService,Completion ...

  8. 戏(细)说Executor框架线程池任务执行全过程(上)

    一.前言 1.5后引入的Executor框架的最大优点是把任务的提交和执行解耦.要执行任务的人只需把Task描述清楚,然后提交即可.这个Task是怎么被执行的,被谁执行的,什么时候执行的,提交的人就不 ...

  9. 戏(细)说Executor框架线程池任务执行全过程(下)

    上一篇文章中通过引入的一个例子介绍了在Executor框架下,提交一个任务的过程,这个过程就像我们老大的老大要找个老大来执行一个任务那样简单.并通过剖析ExecutorService的一种经典实现Th ...

随机推荐

  1. C++学习笔记 封装 继承 多态 重写 重载 重定义

    C++ 三大特性 封装,继承,多态 封装 定义:封装就是将抽象得到的数据和行为相结合,形成一个有机的整体,也就是将数据与操作数据的源代码进行有机的结合,形成类,其中数据和函数都是类的成员,目的在于将对 ...

  2. 几种获取IP 根据IP获取地址的方法 JS,第三方 新浪 网易 腾讯

    第一种是利用纯真ip数据库,这个可以在网上找到很多,缺点是更新有点慢. 第二种是利用门户网站的接口 目前已知的有腾讯.新浪.网易.搜狐和Google提供IP地址查询API,但是找得到的只有腾讯.新浪和 ...

  3. lua coroutine for iterator

    背景 前面的文章演示了使用闭包函数实现 状态的迭代器. 本文演示使用 coroutine来产生迭代器的例子. coroutine迭代器例子 -- 遍历二叉树 local binary_tree = { ...

  4. SSIS 连接ORACLE 无法从 SQL 命令中提取参数的解决方案

    第一步:  定义包变量:maxdate 类型为String  定义包变量:sqlStatement类型为String,值为:select * from i_out_serv_mon 第二步:  取&q ...

  5. Vim命令

    多行缩进: shift+v >或者< 撤销: :u

  6. eclipse tomcat 集成

    1. 下载 Tomcat        作者选择的是 Tomcat6,下载地址:http://tomcat.apache.org/download-60.cgi,选择绿色版的 zip 进行下载(目前最 ...

  7. zepto和jquery的区别,zepto的不同使用8条小结

    说到诡异事件发生的原因,自然是想到两者之间的差异性. 首先是效果: jquery中有fadeIn和fadeOut两个效果,用来实现渐隐渐显的效果,这个在PC端自然是常用的效果.然后我们前端组的组员Mr ...

  8. linux昨天修改的文件

    find ./ -mtime :返回最近24小时内修改过的文件. find ./ -mtime : 返回的是前48~24小时修改过的文件.而不是48小时以内修改过的文件. Linux查找文件内容的常用 ...

  9. Python各式装饰器

    Python装饰器,分两部分,一是装饰器本身的定义,一是被装饰器对象的定义. 一.函数式装饰器:装饰器本身是一个函数. 1.装饰函数:被装饰对象是一个函数 [1]装饰器无参数: a.被装饰对象无参数: ...

  10. Android使用ndk-stack获取so奔溃堆栈

    利用NDK做开发,因为各种原因的不小心,导致了闪退问题,没有stack的话,很难查到问题的所在.这时候ndk-stack出场了. 先看看如下DUMP信息: ********** Crash dump: ...