Java ExecutorService

2025年1月11日 | 阅读 8 分钟

Java ExecutorService 是一个接口,它允许我们在线程上异步执行任务。它位于 `java.util.concurrent` 包中。ExecutorService 帮助维护一个线程池并将任务分配给它们。如果任务数量多于可用线程,它还提供了一个设施,可以将任务排队等待,直到有空闲线程可用。

此外,ExecutorService 接口还提供了控制任务执行方式的方法。这些方法包括 `submit(Runnable task)` 和 `submit(Callable<T> task)`,它们提交任务以供执行并返回一个反映任务等待结果的 Future。此外,`shutdown()` 方法可以优雅地终止 ExecutorService,它允许已提交的任务在终止之前完成。

另一种技术 `shutdownNow()` 会立即停止待处理任务的处理,并尝试停止所有当前正在运行的进程。此外,`awaitTermination(long timeout, TimeUnit unit)` 方法会阻塞,直到所有任务在发出 shutdown 请求后执行完毕,或者发生超时,或者当前线程被中断,以先发生的为准。对于 Java 程序,此接口提供了一种灵活有效的方式来同时处理多个任务。

Java ExecutorService

Java ExecutorService 的方法

方法描述
boolean awaitTermination(long timeout, TimeUnit unit)此方法在收到 shutdown 请求后,会阻塞调用线程,直到所有任务都完成执行,或达到指定超时时间,或当前线程被中断,以先发生的为准。
<T> ListinvokeAll(Collection<? extends Callable<T>> tasks)此方法执行给定任务列表,并在所有任务完成后返回包含所有任务结果的 Future 列表。
<T> ListinvokeAll(Collection<? extends Callable<T>> tasks, long timeout, TimeUnit unit)此方法执行给定任务列表,并返回包含所有任务结果的 Future 列表,如果任务在超时前完成,则返回结果,否则在超时后返回。
<T> T invokeAny(Collection<? extends Callable<T>> tasks)此方法执行给定任务列表,并返回第一个成功完成而未抛出任何异常的任务的结果。
<T> T invokeAny(Collection<? extends Callable<T>> tasks, long timeout,TimeUnit unit)此方法执行给定任务列表,并返回在超时之前第一个成功完成而未抛出任何异常的任务的结果。
boolean isShutdown()此方法返回给定的执行器是否已关闭。
boolean isTerminated()此方法在 shutdown 后,如果所有任务都已执行完毕,则返回 true。
void shutdown()此方法允许 ExecutorService 完成先前提交的任务,并且不允许接受任何新任务。
列表shutdownNow()此方法停止所有当前正在执行的任务,停止执行队列中的任务,并返回队列中任务的列表。
<T> Future<T> submit(Callable<T> task)此方法提交一个返回值任务以供执行,并返回代表任务待定结果的 Future。
Future<?> submit(Runnable task)此方法提交一个任务以供执行,并返回代表该任务的 Future。成功完成后返回 null。
<T> Future<T> submit(Runnable task, T result)此方法提交一个任务以供执行,并返回代表该任务的 Future。
void execute(Runnable command)在将来的某个时间点执行给定的命令。
<T> CompletionService<T> newCompletionService()创建一个新的 CompletionService,该服务使用给定的执行器来运行任务并返回它。
ScheduledFuture<?> schedule(Runnable command, long delay, TimeUnit unit)安排给定的命令在指定的延迟后运行,并返回代表该任务的 ScheduledFuture。
ScheduledFuture<?> schedule(Callable<V> callable, long delay, TimeUnit unit)安排给定的 callable 在指定的延迟后运行,并返回代表该任务的 ScheduledFuture。
ScheduledFuture<?> scheduleAtFixedRate(Runnable command, long initialDelay, long period, TimeUnit unit)创建并执行一个周期性操作,该操作在给定的初始延迟后首次启用,然后以给定的周期执行。
ScheduledFuture<?> scheduleWithFixedDelay(Runnable command, long initialDelay, long delay, TimeUnit unit)创建并执行一个周期性操作,该操作在给定的初始延迟后首次启用,然后每次执行完成后与下一次执行开始之间有给定的延迟。

ExecutorService Java 程序

文件名: ExecutorServiceExample.java

输出

Java ExecutorService

解释

在此程序中,我们创建一个具有十个线程的 ExecutorService,并为其分配一个匿名的 Runnable 实现,该实现执行打印 "ExecutorService" 的任务,并在任务完成后关闭 ExecutorService。

如何使用 Java ExecutorService?

实例化 ExecutorService

我们可以使用 Java ExecutorService 来创建单个线程、线程池或计划线程池。Executors 类提供了工厂方法来实例化 ExecutorService,如下所示:

为 ExecutorServices 分配任务

要为 ExecutorService 分配任务,我们可以使用以下方法:

  • execute(Runnable task)
  • submit(Runnable task) / submit(Callable<T> task)
  • invokeAny(Collection<? extends Callable<T>> tasks)
  • invokeAll(Collection<? extends Callable<T>> tasks)

使用 execute() 方法为 ExecutorService 分配任务的示例

Java ExecutorService 的 execute() 方法接受一个 Runnable 对象并异步执行其任务。调用 execute 方法后,我们调用 shutdown 方法,该方法会阻止其他任务排队到 executorService 中。

文件名: ExecutorServiceExample.java

输出

ExecutorService

解释

此 Java 程序演示了如何使用通过 Executors.newSingleThreadExecutor() 获取的单线程 ExecutorService。创建执行器服务后,使用 execute 方法提交一个由实现 Runnable 接口的匿名内部类表示的任务。在此任务的 run() 方法中,将 "ExecutorService" 打印到控制台。

最后,在提交的任务执行完成后,调用执行器服务的 shutdown 方法以优雅地关闭它。这确保了执行器服务不会接受新任务,并等待现有任务完成后终止。

使用 submit() 方法为 ExecutorService 分配任务的示例

submit() 方法接受一个 Runnable 对象并返回一个 Future 对象。此对象稍后用于检查 Runnable 是否已完成执行。

文件名: ExecutorServiceExample.java

输出

ExecutorService

解释

此 Java 程序使用 Executors.newSingleThreadExecutor() 创建一个单线程的 ExecutorService。然后,它使用 submit 方法向执行器服务提交一个任务,将 "ExecutorService" 打印到控制台。这演示了单线程执行器服务的异步任务执行。

使用 invokeAny() 方法为 ExecutorService 分配任务的示例

invokeAny() 方法接受一个 Callable 对象集合或实现 Callable 的类的对象。此方法返回第一个成功执行的 Callable 对象的 Future 对象。

文件名: ExecutorServiceExample.java

输出

result = Task 1

解释

此 Java 程序以新方式演示了使用通过 Executors 获取的单线程 ExecutorService。它使用 HashSet 生成一组 Callable 任务,每个任务返回一个代表任务的文本。然后将这些任务添加到可调用对象列表中。然后将可调用对象列表传递给 ExecutorService 的 invokeAny 方法,该方法返回一个已完成的单个作业的结果。一旦所有作业都完成执行,结果就会显示在控制台上,最后通过 shutdown 方法对执行器服务进行平滑终止。

使用 invokeAll() 方法为 ExecutorService 分配任务的示例

invokeAll() 方法接受一个包含任务的 Callable 对象集合,并返回一个包含所有任务结果的 Future 对象列表。

文件名: ExecutorServiceExample.java

输出

future.get = Task 1
future.get = Task 3
future.get = Task 2

解释

此 Java 程序以新方式利用通过 Executors 获取的单线程 ExecutorService。它在创建 Callable 任务后将它们添加到集合中。然后将可调用对象集合传递给 ExecutorService 的 invokeAll 方法,该方法返回一个 Future 对象列表,这些对象反映了任务的结果。之后,通过迭代 Future 列表,打印每个任务的输出。最后,当所有作业都完成执行后,通过使用 shutdown 方法对执行器服务进行平滑终止。

如何关闭 ExecutorService?

一旦我们完成了分配给 ExecutorService 的任务,我们就必须关闭它,因为 ExecutorService 在不同的线程上执行任务。如果我们不关闭 ExecutorService,线程将继续运行,JVM 将不会关闭。

关闭过程可以通过以下三种方法完成:

1. shutdown() 方法

此方法启动有序关闭,其中将执行先前提交的任务,但不再接受新任务。它允许 ExecutorService 在完成所有已提交任务后优雅地关闭。

2. shutdownNow() 方法

此方法尝试停止所有当前正在执行的任务,停止处理等待中的任务,并返回等待执行的任务列表。它会强制终止 ExecutorService,可能会中断正在进行的任务。

3. awaitTermination() 方法

在收到 shutdown 请求后,阻塞调用线程,直到所有任务都完成执行,或者发生超时,或者当前线程被中断,以先发生的为准。此方法允许调用线程在继续进行其他操作之前等待 ExecutorService 的终止。


下一个主题Java 教程