JAVA的Executor框架
Executor框架分离了任务的创建和执行。JAVA SE5的java.util.concurrent包中的执行器(Executor)管理Thread对象,从而简化了并发编程。Executor引入了一些功能类来管理和使用线程Thread,其中包括线程池,Executor,Executors,ExecutorService,CompletionService,Future,Callable等.
1.Executor接口
public interface Executor{
void execute(Runnable task);
}
Executor接口是Executor框架中最基础的部分,定义了一个用于执行Runnable的execute方法。它没有直接的实现类,有一个重要的子接口ExecutorService.执行已提交的Runnable任务的对象。此接口提供一种将任务提交与每个任务将如何运行的机制(包括线程使用的细节、调度等)分离开来的方法。通常使用 Executor而不是显式地创建线程。例如,可能会使用以下方法,而不是为一组任务中的每个任务调用 new Thread(new(RunnableTask())).start():
Executor executor = anExecutor;
executor.execute(new RunnableTask1());
executor.execute(new RunnableTask2());
...
内存一致性效果:线程中将Runnable
对象提交到 Executor之前的操作 happen-before其执行开始(可能在另一个线程中)。
2.ExecutorService
public interface ExecutorService extends Executor {
void shutdown();//关闭方法,调用后执行之前提交的任务,不再接受新的任务
List<Runnable> shutdownNow();//从语义上可以看出是立即停止的意思,将暂停所有等待处理的任务并返回这些任务的列表
boolean isShutdown();// 判断执行器是否已经关闭
boolean isTerminated();//关闭后所有任务是否都已完成
boolean awaitTermination(long timeout, TimeUnit unit)throws InterruptedException;
<T> Future<T> submit(Callable<T> task);//提交一个Callable任务
<T> Future<T> submit(Runnable task, T result);//提交一个Runable任务,result要返回的结果
Future<?> submit(Runnable task);//提交一个任务
//执行所有给定的任务,当所有任务完成,返回保持任务状态和结果的Future列表
<T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks)throws InterruptedException;
//执行给定的任务,当所有任务完成或超时期满时(无论哪个首先发生),返回保持任务状态和结果的 Future 列表。
<T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks,long timeout, TimeUnit unit)
throws InterruptedException;
执行给定的任务,如果某个任务已成功完成(也就是未抛出异常),则返回其结果。
<T> T invokeAny(Collection<? extends Callable<T>> tasks)throws InterruptedException, ExecutionException;
//执行给定的任务,如果在给定的超时期满前某个任务已成功完成(也就是未抛出异常),则返回其结果.
<T> T invokeAny(Collection<? extends Callable<T>> tasks, long timeout, TimeUnit unit)
throws InterruptedException,ExecutionException,TimeoutException;
}
ExecutorService接口继承自Executor接口,定义了终止、提交任务、跟踪任务返回结果等方法。ExecutorService涉及到Runnable、Callable、Future接口,这些接口的具体内容如下。
// 实现Runnable接口的类将被Thread执行,表示一个基本的任务
public interface Runnable {
public abstract void run();// run方法就是它所有的内容,就是实际执行的任务
}
// Callable同样是任务,与Runnable接口的区别在于它接收泛型,同时它执行任务后带有返回内容
public interface Callable<V> {
V call() throws Exception;// 相对于run方法的带有返回值的call方法
}
3.Future:代表异步任务执行的结果
public interface Future<V> {
//尝试取消一个任务,如果这个任务不能被取消(通常是因为已经执行完了),返回false,否则返回true。
boolean cancel(boolean mayInterruptIfRunning);
boolean isCancelled();// 返回代表的任务是否在完成之前被取消了
boolean isDone(); //如果任务已经完成,返回true
//获取异步任务的执行结果,如果任务没执行完将等待
V get() throws InterruptedException, ExecutionException;
//获取异步任务的执行结果(有最长等待时间的限制)。timeout表示等待的时间,unit是它时间单位
V get(long timeout, TimeUnit unit) throws InterruptedException,ExecutionException, TimeoutException;
}
4.ScheduledExecutorService
//可以安排指定时间或周期性的执行任务的ExecutorService
public interface ScheduledExecutorService extends ExecutorService {
//在指定延迟后执行一个任务,只执行一次
public ScheduledFuture<?> schedule(Runnable command,long delay,TimeUnit unit);
//与上面的方法相同,只是接受的是Callable任务
public ScheduledFuture<V> schedule(Callable<V> callable,long delay,TimeUnit unit);
//创建并执行一个周期性的任务,在initialDelay延迟后每间隔period个单位执行一次,时间单位都是unit
// 每次执行任务的时间点是initialDelay, initialDelay+period, initialDelay + 2 * period
public ScheduledFuture<?> scheduleAtFixedRate(Runnable command,long initialDelay, long period, TimeUnit unit);
// 创建并执行一个周期性的任务,在initialDelay延迟后开始执行,在执行结束后再延迟delay个单位开始执行下一次任务,
// 时间单位都是unit.每次执行任务的时间点是initialDelay, initialDelay+(任务运行时间+delay),
// initialDelay + 2 * (任务运行时间+delay)...
public ScheduledFuture<?> scheduleWithFixedDelay(Runnable command,long initialDelay, long delay, TimeUnit unit);
}
5.AbstractExecutorService
//提供ExecutorService的默认实现
public abstract class AbstractExecutorService implements ExecutorService {
//为指定的Runnable和value构造一个FutureTask, value表示默认被返回的Future
protected <T> RunnableFuture<T> newTaskFor(Runnable runnable, T value) {
return new FutureTask<T>(runnable, value);
}
//为指定的Callable创建一个FutureTask
protected <T> RunnableFuture<T> newTaskFor(Callable<T> callable) {
return new FutureTask<T>(callable);
}
// 提交Runnable任务
public Future<?> submit(Runnable task) {
if (task == null)
throw new NullPointerException();
// 通过newTaskFor方法构造RunnableFuture,默认的返回值是null
RunnableFuture<Object> ftask = newTaskFor(task, null);
// 调用具体实现的execute方法
execute(ftask);
return ftask;
}
// 提交Runnable任务
public <T> Future<T> submit(Runnable task, T result) {
if (task == null)
throw new NullPointerException();
//通过newTaskFor方法构造RunnableFuture,默认的返回值是result
RunnableFuture<T> ftask = newTaskFor(task, result);
execute(ftask);
return ftask;
}
//提交Callable任务
public <T> Future<T> submit(Callable<T> task) {
if (task == null)
throw new NullPointerException();
RunnableFuture<T> ftask = newTaskFor(task);
execute(ftask);
return ftask;
}
// doInvokeAny的具体实现(核心内容),其它几个方法都是重载方法,都对这个方法进行调用
// tasks是被执行的任务集,timed标志是否定时的,nanos表示定时的情况下执行任务的限制时间
private <T> T doInvokeAny(Collection<? extends Callable<T>> tasks,boolean timed,long nanos)
throws InterruptedException, ExecutionException, TimeoutException {
if (tasks==null)// tasks空判断
throw new NullPointerException();
int ntasks=tasks.size();// 任务数量
if (ntasks == 0)
throw new IllegalArgumentException();
List<Future<T>> futures= new ArrayList<Future<T>>(ntasks);// 创建对应数量的Future返回集
ExecutorCompletionService<T> ecs =new ExecutorCompletionService<T>(this);
try {
ExecutionException ee = null; //执行异常
long lastTime = (timed)? System.nanoTime(): 0; //System.nanoTime()根据系统计时器当回当前的纳秒值
Iterator<? extends Callable<T>> it = tasks.iterator();//获取任务集的遍历器
futures.add(ecs.submit(it.next()));//向执行器ExecutorCompletionService提交一个任务,并将结果加入futures中
--ntasks;//修改任务计数器
int active =1;//活跃任务计数器
for (;;) {
Future<T> f = ecs.poll();//获取并移除代表已完成任务的Future,如果不存在,返回null
if (f== null) {
//没有任务完成,且任务集中还有未提交的任务
if (ntasks > 0) {
--ntasks;//剩余任务计数器减
futures.add(ecs.submit(it.next()));//提交任务并添加结果
++active; //活跃任务计数器加
}
//没有剩余任务,且没有活跃任务(所有任务可能都会取消),跳过这一次循环
else if (active==0)
break;
else if (timed) {
//获取并移除代表已完成任务的Future,如果不存在,会等待nanos指定的纳秒数
f = ecs.poll(nanos, TimeUnit.NANOSECONDS);
if (f == null)
throw new TimeoutException();
// 计算剩余可用时间
long now = System.nanoTime();
nanos -= now - lastTime;
lastTime = now;
}
else
// 获取并移除表示下一个已完成任务的未来,等待,如果目前不存在。
// 执行到这一步说明已经没有任务任务可以提交,只能等待某一个任务的返回
f = ecs.take();
}
// f不为空说明有一个任务完成了
if (f!=null) {
--active;//已完成一个任务,所以活跃任务计数减
try {
return f.get();//返回该任务的结果
} catch (InterruptedException ie) {
throw ie;
} catch (ExecutionException eex) {
ee = eex;
} catch (RuntimeException rex) {
ee = new ExecutionException(rex);
}
}
}
// 如果没有成功返回结果则抛出异常
if (ee == null)
ee = new ExecutionException();
throw ee;
} finally {
// 无论执行中发生异常还是顺利结束,都将取消剩余未执行的任务
for (Future<T> f : futures)
f.cancel(true);
}
}
public <T> T invokeAny(Collection<? extends Callable<T>> tasks)
throws InterruptedException, ExecutionException {
try {
return doInvokeAny(tasks, false,0);//非定时任务的doInvokeAny调用
} catch (TimeoutException cannotHappen) {
assert false;
return null;
}
}
// 定时任务的invokeAny调用,timeout表示超时时间,unit表示时间单位
public <T> T invokeAny(Collection<? extends Callable<T>> tasks,long timeout,TimeUnit unit)
throws InterruptedException,
ExecutionException, TimeoutException {
return doInvokeAny(tasks, true, unit.toNanos(timeout));
}
// 无超时设置的invokeAll方法
public <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks)
throws InterruptedException {
// 空任务判断
if (tasks == null)
throw new NullPointerException();
// 创建大小为任务数量的结果集
List<Future<T>> futures = new ArrayList<Future<T>>(tasks.size());
//是否完成所有任务的标记
boolean done=false;
try {
// 遍历并执行任务
for (Callable<T> t : tasks) {
RunnableFuture<T> f = newTaskFor(t);
futures.add(f);
execute(f);
}
// 遍历结果集
for (Future<T> f : futures) {
// 如果某个任务没完成,通过f调用get()方法
if (!f.isDone()) {
try {
//get方法等待计算完成,然后获取结果(会等待)。所以调用get后任务就会完成计算,否则会等待
f.get();
} catch (CancellationException ignore) {
} catch (ExecutionException ignore) {
}
}
}
done =true;//标志所有任务执行完成
return futures;// 返回结果
} finally {
// 假如没有完成所有任务(可能是发生异常等情况),将任务取消
if (!done)
for (Future<T> f : futures)
f.cancel(true);
}
}
// 超时设置的invokeAll方法
public <T> List<Future<T>>invokeAll(Collection<? extends Callable<T>> tasks,long timeout,TimeUnit unit)throws InterruptedException {
if (tasks == null||unit == null)//需要执行的任务集为空或时间单位为空,抛出异常
throw new NullPointerException();
long nanos = unit.toNanos(timeout);//将超时时间转为纳秒单位
List<Future<T>> futures = new ArrayList<Future<T>>(tasks.size());//创建任务结果集
boolean done = false;//是否全部完成的标志
try {
//遍历tasks,将任务转为RunnableFuture
for (Callable<T> t : tasks)
futures.add(newTaskFor(t));
long lastTime = System.nanoTime(); //记录当前时间(单位是纳秒)
Iterator<Future<T>> it = futures.iterator();//获取迭代器
// 遍历
while (it.hasNext()) {
execute((Runnable)(it.next()));//执行任务
long now = System.nanoTime();//记录当前时间
nanos -= now - lastTime;//计算剩余可用时间
lastTime = now;//更新上一次执行时间
//超时,返回保存任务状态的结果集
if (nanos <= 0)
return futures;
}
for (Future<T> f : futures) {
//如果有任务没完成
if (!f.isDone()) {
//时间已经用完,返回保存任务状态的结果集
if (nanos <= 0)
return futures;
try {
// 获取计算结果,最多等待给定的时间nanos,单位是纳秒
f.get(nanos, TimeUnit.NANOSECONDS);
} catch (CancellationException ignore) {
} catch (ExecutionException ignore) {
} catch (TimeoutException toe) {
return futures;
}
// 计算可用时间
long now = System.nanoTime();
nanos -= now - lastTime;
lastTime = now;
}
}
done = true;//修改是否全部完成的标记
return futures;//返回结果集
} finally {
//假如没有完成所有任务(可能是时间已经用完、发生异常等情况),将任务取消
if (!done)
for (Future<T> f : futures)
f.cancel(true);
}
}
}
JAVA的Executor框架的更多相关文章
- Java的Executor框架和线程池实现原理
Java的Executor框架 1,Executor接口 public interface Executor { void execute(Runnable command); } Executor接 ...
- Java的Executor框架和线程池实现原理(转)
ExecutorService接口继承自Executor接口,定义了终止.提交,执行任务.跟踪任务返回结果等方法 1,execute(Runnable command):履行Ruannable类型的任 ...
- Java Executor框架使用
Java Executor框架是Jdk1.5之后推出的,是为了更加方便的开发多线程应用而封装的框架: 相比传统的Thread类,Java Executor使用方便,性能更好,更易于管理,而且支持线程池 ...
- java并发编程(十七)Executor框架和线程池
转载请注明出处:http://blog.csdn.net/ns_code/article/details/17465497 Executor框架简介 在Java 5之后,并发编程引入了一堆新的启动 ...
- Java并发和多线程(二)Executor框架
Executor框架 1.Task?Thread? 很多人在学习多线程这部分知识的时候,容易搞混两个概念:任务(task)和线程(thread). 并发编程可以使我们的程序可以划分为多个分离的.独立运 ...
- java并发编程-Executor框架
Executor框架是指java 5中引入的一系列并发库中与executor相关的一些功能类,其中包括线程池,Executor,Executors,ExecutorService,Completion ...
- Java并发——线程池Executor框架
线程池 无限制的创建线程 若采用"为每个任务分配一个线程"的方式会存在一些缺陷,尤其是当需要创建大量线程时: 线程生命周期的开销非常高 资源消耗 稳定性 引入线程池 任务是一组逻辑 ...
- Java Executor 框架
Java Executor 框架 Executor框架是指java5中引入的一系列并发库中与executor相关的功能类,包括Executor.Executors. ExecutorService.C ...
- 转:【Java并发编程】之十九:并发新特性—Executor框架与线程池(含代码)
Executor框架简介 在Java5之后,并发编程引入了一堆新的启动.调度和管理线程的API.Executor框架便是Java 5中引入的,其内部使用了线程池机制,它在java.util.coc ...
随机推荐
- spring+mybatis之声明式事务管理初识(小实例)
前几篇的文章都只是初步学习spring和mybatis框架,所写的实例也都非常简单,所进行的数据访问控制也都很简单,没有加入事务管理.这篇文章将初步接触事务管理. 1.事务管理 理解事务管理之前,先通 ...
- jenkins+docker+maven+svn
环境介绍 1. 软件需求 Jenkins 本次实验所用版本1.5.1 下载链接:https://jenkins.io/index.html Docker 本次实验所用版本 17.03. ...
- 数位dp初步——数位dp的两种方式
数位dp:一类统计区间[L,R]内某种符合规定的数字个数的题目.特征是R的范围会很大,O(N)范围内无法完成. 一般而言,解决这类题目有两种方式,一种是递推,另一种是记忆化搜索. 递推: 1)利用dp ...
- Linux怎样创建FTP服务器
在创建FTP服务器之有先命令: ps -ef |grep vsftpd 查一下系统有没有安装vsftpd这个服务器,如果出现如下图所示的界面说明没有安装. 然后再执行:yum install vs ...
- 翻译一篇文章:It's Difficult to Grow a Test Developer(成为测试开发工程师的艰辛)
翻译一篇文章:It's Difficult to Grow a Test Developer(成为测试开发工程师的艰辛) 以下文章是送给来poptest学习测试开发工程师的学员们,很多人想测试工程 ...
- 老李分享:Web Services 架构 1
老李分享:Web Services 架构 poptest是国内唯一一家培养测试开发工程师的培训机构,以学员能胜任自动化测试,性能测试,测试工具开发等工作为目标.如果对课程感兴趣,请大家咨询qq:9 ...
- Javaweb快速学习
孙卫琴老师的javaweb一书已经买了很多年,由于很厚一直也没有去好好阅读下, 项目发布后有闲暇时间,决定快速学习了,毕竟很多概念和知识主要还是复习. 对于互联网,我们可以简单认为浏览器就是会人类语言 ...
- EDP转换IC NCS8803:HDMI转EDP芯片
HDMI-to-eDP Converter w/ scaler1 Features Embedded-DisplayPort (eDP) Output 1/2/4-lane eDP @ 1 ...
- json解包与json封包
首先,对两个名词进行简单的说明: 1.NSData 用来存储二进制的数据类型.NSData类提供了一种简单的方式,它用来设置缓冲区.将文件的内容读入缓冲区,或将缓冲区的内容写到一个文件.不变缓冲区(N ...
- 【微信开发】PHP中奖概率经典算法实例
$arr=array("50","30","20"); //这里简单列出三个数 $pro = array_sum($arr); // 概率数 ...