文档章节

Executor框架详解

AbeJeffrey
 AbeJeffrey
发布于 2017/04/04 22:06
字数 2783
阅读 291
收藏 6

任务是一组逻辑工作单元,线程是使任务异步执行的机制。下面分析两种通过创建线程来执行任务的策略。

1 将所有任务放在单个任务中串行执行;

2 为每个任务创建单独的线程来执行

实际上两种方式都存在一些严重的缺陷。串行执行的问题在于其糟糕的响应和吞吐量;而为每个任务单独创建线程的问题在于资源管理的复杂性,容易造成资源的浪费和过度消耗,影响系统的稳定性。为了提高任务执行的效率和系统的吞吐量,合理分配和利用资源,线程池应运而生。

什么是线程池?

线程池是指管理一组同构工作线程的资源池。线程池与工作队列密切相关的,其中工作队列中保存了所有等待执行的任务。工作者线程的任务是从工作队列中获取一个任务,执行任务,然后回线程池并等待下一个任务。

Executor框架

Executor框架是java5引入用于执行Runnable任务的接口,但并不是一个简单的接口,Executor为实现灵活且强大的异步任务执行框架提供了基础,该框架支持多种不同类型的任务执行策略。它提供了一种标准的方法将任务的提交过程与执行过程解耦开来,并用Runnable来表示任务。Executor的实现还提供了对生命周期的支持,以及统计信息收集、应用程序管理和性能监视等机制。

Executor基于生产者-消费者模式,提交任务的操作相当于生产者,执行任务的操作则相当于消费者。

Executor框架包括:线程池,Executor,Executors,ExecutorService,CompletionService,Future,Callable等。类图关系如下:

Executor接口定义了一个方法execute(Runnable command),该方法接收一个Runable实例,它用来执行一个任务。

void execute(Runnable command);

ExecutorService

ExecutorService接口继承自Executor接口,它提供了更丰富的方法,比如,关闭线程池,以及为跟踪一个或多个异步任务执行状况而生成 Future 的方法。下面详细介绍ExecutorService接口中各方法的功能。

void shutdown();

 shutdown()方法来平滑地关闭 ExecutorService,调用该方法后,ExecutorService将停止接受新任务,但会执行完已经提交的任务(一类是已经在执行的,另一类是还没有开始执行的)。当所有已经提交的任务执行完毕后关闭ExecutorService。

List<Runnable> shutdownNow();

调用该方法,则将尝试停止所有正在执行的任务,暂停处理正在等待的任务,并返回正在等待任务的列表。

注意:该方法无法保证能够停止正在执行的任务,通常是通过Thread.interrupt()向任务发送一个中断信号,如果任务本身并不响应中断则无法停止任务。

boolean isShutdown();

ExecutorService是否已经关闭。

boolean isTerminated();

关闭ExecutorService后所有任务都已完成则返回true,除非调用了shutdown 或 shutdownNow,否则 isTerminated 永不为 true。

boolean awaitTermination(long timeout, TimeUnit unit) throws InterruptedException;

shutdown请求发生超时或当前线程发生中断,无论先发生哪一个,都将导致阻塞直到所有任务执行完成。

<T> Future<T> submit(Callable<T> task);

提交一个具Callable任务用于执行,返回一个表示任务执行结果的Future。该 Future 的 get 方法在成功完成时将会返回该任务的结果。

<T> Future<T> submit(Runnable task, T result);

提交一个 Runnable 任务用于执行,并返回一个表示该任务执行结果的 Future。该 Future 的 get 方法在成功完成时将会返回给定的结果。

Future<?> submit(Runnable task);

提交一个 Runnable 任务用于执行,并返回一个表示该任务执行结果的 Future。该 Future 的 get 方法在成功完成时将会返回null。

<T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks) throws InterruptedException;

执行给定的任务列表,当所有任务完成时,返回保持任务状态和结果的 Future 列表。返回列表的所有元素的Future.isDone为 true。

注意:可以正常地或通过抛出异常来终止已完成 任务。如果正在进行此操作时修改了给定的 collection,则此方法的结果是不确定的。

<T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks,long timeout, TimeUnit unit)
        throws InterruptedException;

执行给定的任务列表,当所有任务完成或达到超时时限,返回保持任务状态和结果的 Future 列表。返回列表的所有元素的Future.isDone为 true。一旦返回,取消没有完成的任务。(超时返回)

注意:可以正常地或通过抛出异常来终止已完成 任务。如果正在进行此操作时修改了给定的 collection,则此方法的结果是不确定的。

<T> T invokeAny(Collection<? extends Callable<T>> tasks) 
               throws InterruptedException, ExecutionException;

执行给定的任务列表,如果某个任务已成功完成(未抛出异常),则返回其结果。一旦正常或异常返回后,则取消尚未完成的任务。

注意:如果正在进行此操作时修改了给定的 collection,则此方法的结果是不确定的。

<T> T invokeAny(Collection<? extends Callable<T>> tasks,long timeout, TimeUnit unit)
        throws InterruptedException, ExecutionException, TimeoutException;

执行给定的任务列表,如果达到超时时限或某个任务已成功完成(未抛出异常),则返回其结果。一旦正常或异常返回后,则取消尚未完成的任务。

注意:如果正在进行此操作时修改了给定的 collection,则此方法的结果是不确定的。

综上,ExecutorService的生命周期包括三种状态:运行、关闭、终止。创建后便进入运行状态,当调用了shutdown()方法时,便进入关闭状态,此时意味着ExecutorService不再接受新的任务,当有已经提交了的任务执行完后,便到达终止状态。如果不调用shutdown()方法,ExecutorService会一直处在运行状态,不断接收新的任务,执行新的任务。此外,ExecutorService还提供了大量任务异步执行的API,进一步扩展了Executor执行异步任务的能力。接下来介绍Executor是如何支持调度任务执行的。

ScheduledExecutorService

ScheduledExecutorService主要用于实现给定的延迟后执行或定时执行指定的任务,也就是常说的调度任务。其所有 schedule 方法都接受相对 延迟和周期作为参数,而不是绝对的时间或日期。主要提供了以下几个重要方法:

 public ScheduledFuture<?> schedule(Runnable command,long delay, TimeUnit unit);

给定延迟执行一次指定的任务command,执行完成后ScheduledFuture返回null

public <V> ScheduledFuture<V> schedule(Callable<V> callable,long delay, TimeUnit unit);

给定延迟执行一次指定的任务callable,并返回保存任务执行结果的ScheduledFuture。

public ScheduledFuture<?> scheduleAtFixedRate(Runnable command,
                                                  long initialDelay,
                                                  long period,
                                                  TimeUnit unit);

按指定频率周期性执行任务,任务在initialDelay后首次执行,且任务在(initialDelay+=period)后周期性地执行下去,只能通过执行程序的取消或终止方法来终止该任务。

注意:如果任务的任何一次执行遇到异常,将不再执行;如果任务的任何一次执行花费比其周期更长的时间,则将推迟后续执行,但不会同时执行。

public ScheduledFuture<?> scheduleWithFixedDelay(Runnable command,
                                                     long initialDelay,
                                                     long delay,
                                                     TimeUnit unit);

按指定频率间隔周期性地执行任务,任务在initialDelay后首次执行,后续执行将在当前执行终止后间隔delay开始执行,只能通过执行程序的取消或终止方法来终止该任务。

注意:如果任务的任何一次执行遇到异常,将不再执行。

CompletionService

CompletionService是将生产新的异步任务与消费已完成任务的结果分离开来的服务,生产者负责 submit 要执行的任务,消费者负责take已完成的任务,并按照完成这些任务的顺序处理它们的结果。

CompletionService需要一个单独Executor来实际执行任务,其内部只负责管理一个完成队列。其主要操作说明:

Future<V> poll();

获取并移除表示下一个已完成任务的 Future,如果不存在这样的任务,则返回 null。获取并移除表示下一个已完成任务的 Future,如果不存在这样的任务,则返回 null。

Future<V> poll(long timeout, TimeUnit unit) throws InterruptedException;

获取并移除表示下一个已完成任务的 Future,如果目前不存在这样的任务,则将等待指定的时间。

Future<V> take() throws InterruptedException;

获取并移除表示下一个已完成任务的 Future,如果目前不存在这样的任务,则等待。

 Future<V> submit(Callable<V> task);

提交要执行的值返回任务,并返回表示挂起的任务结果的 Future。在完成时,可能会提取或轮询此任务。

Future<V> submit(Runnable task, V result);

提交要执行的 Runnable 任务,并返回一个表示任务完成的 Future,可以提取或轮询此任务。

Future

Future 表示异步计算的结果。它提供了检查计算是否完成的方法,以等待计算的完成,并获取计算的结果。计算完成后只能使用 get 方法来获取结果,计算完成前可根据需要阻塞此方法。可调用cancel方法取消计算,计算完成则无法取消。

若想通过Future实现计算的可取消功能,但无需提供返回结果,则可以声明 Future<?> 形式类型、并返回 null 作为底层任务的结果。

部分方法说明:

boolean cancel(boolean mayInterruptIfRunning);

尝试取消任务的执行,如果任务已完成、或已取消,或者由于某些其他原因而无法取消,返回false。当调用 cancel 时,如果调用成功,而此任务尚未启动,则任务将永不运行。如果任务已经启动,则 mayInterruptIfRunning 参数确定是否应该以试图停止任务的方式来中断执行此任务的线程。

此方法返回后,后续调用isDone()方法将一直返回true;如果此方法返回true,后续调用isCancelled()将一直返回true。

V get() throws InterruptedException, ExecutionException;

等待计算完成,然后获取其结果。

RunnableFuture

作为Runnable任务的Future,成功执行 run 方法可以完成 Future 并允许访问其结果。

void run();

如果任务未被取消,将此 Future 设置为计算的结果。

欢迎指出本文有误的地方,转载请注明原文出处https://my.oschina.net/7001/blog/873089

© 著作权归作者所有

AbeJeffrey
粉丝 51
博文 43
码字总数 116095
作品 0
杭州
高级程序员
私信 提问
加载中

评论(0)

扣丁学堂大数据培训Spark架构运行及优势详解

  今天扣丁学堂大数据培训给大家介绍一下关于大数据开发中Spark架构运行详解及其优势详解,首先spark是一种分布式的计算框架。类似于大数据开发中Hadoop生态圈的MapReduce,计算思想和MR非...

扣丁学堂
2018/08/14
0
0
mybatis缓存机制详解(一)——Cache

缓存概述 在mybatis中,缓存的功能由根接口Cache(org.apache.ibatis.cache.Cache)定义。整个体系采用装饰器设计模式,数据存储和缓存的基本功能由PerpetualCache(org.apache.ibatis.cache...

拉风小野驴
2016/02/24
4.2K
1
mybatis核心组件详解——Executor(未完待续)

概述 Executor(org.apache.ibatis.executor.Executor),执行器。 public interface Executor { ResultHandler NORESULTHANDLER = null; int update(MappedStatement ms, Object parameter)......

拉风小野驴
2016/02/24
779
1
Java多线程学习(八)线程池与Executor 框架

Java面试通关手册(Java学习指南,欢迎Star,会一直完善下去,欢迎建议和指导):https://github.com/Snailclimb/JavaGuide 历史优质文章推荐: Java并发编程指南专栏 分布式系统的经典基础理...

snailclimb
2018/05/31
0
0
我的第一本著作:Spark技术内幕上市!

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/anzhsoft2008/article/details/48594363 现在各大网站销售中! 京东:http://item.jd.com/11770787.html 当当...

anzhsoft
2015/09/20
0
0

没有更多内容

加载失败,请刷新页面

加载更多

Ansible Playbook 变量传递

1. 可以在命令行传递变量 ansible-playbook -e "host=dev user=root" vars.yaml ---- name: var test hosts: "{{ host }}" tasks: - name: var test debug: msg: "H......

osc_ho8dcqsx
27分钟前
46
0
C#.NET 前端大文件上传

IE的自带下载功能中没有断点续传功能,要实现断点续传功能,需要用到HTTP协议中鲜为人知的几个响应头和请求头。 一. 两个必要响应头Accept-Ranges、ETag 客户端每次提交下载请求时,服务端都...

osc_ozapt2g1
29分钟前
73
0
[Gin] gin.H{} 与 map[string]interface{}

gin.H 中的 H 是对 map[string]interface{} 定义的新类型,用来简化生成 map 数据时的书写。 // H is a shortcut for map[string]interface{}type H map[string]interface{} map[string]int......

osc_1x6ycmfm
30分钟前
52
0
手机诞生 47 年后,人们已不再用它来打电话

摘要 近半个世纪的兴衰沉浮,手机已经早已不是当年模样。 1973 年 4 月 3 日,当摩托罗拉工程师马丁·库珀用重量超过 900 克的「大哥大」成功拨出电话时或许不会想到,43 年后的今天手机竟然...

osc_ze3jj3wd
31分钟前
57
0
数据库系统概论--SQL-`写一半不想写了,不知道为啥`

SQL语句还是多去用才能掌握,再多理论,白搭 SQL概述 SQL的产生与发展 SQL的特点 SQL功能十分强大,针对数据的操作,核心功能只用9个动词就可以完成。而且其语句有点类似英语口语一看基本就能...

osc_cdixgndu
32分钟前
55
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部