Executor框架详解 4年前

代码工具
681
Executor框架详解

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

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

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

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

什么是线程池?

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

Executor框架

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

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

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

Executor框架详解

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

image
whalepikapika
不弄丢自己,是爱情的底线。
1
发布数
0
关注者
680
累计阅读

热门教程文档

Redis
14小节
Flutter
105小节
Spring Cloud
8小节
Maven
5小节
MyBatis
19小节
广告