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