ExecutorService 类方法介绍及示例
概述
在Java中,ExecutorService
是一个接口,它提供了一种方式来管理异步任务的执行。ExecutorService
为线程池提供了框架,允许你控制并发执行任务的各个方面,包括任务的调度、任务的取消、任务的结果处理,以及执行过程中可能出现的异常。
使用ExecutorService
可以避免显式地创建和管理线程,这有助于减少资源消耗和提高应用程序的响应性。通过ExecutorService
,你可以提交Runnable
或Callable
任务给线程池执行,并获取Future
对象来跟踪异步计算的结果。
核心概念
ExecutorService
的核心概念主要围绕着线程池和任务管理。以下是 ExecutorService
的几个核心概念:
- 线程池:
- 线程池是一个管理线程集合的框架,它负责线程的创建、销毁、复用和调度。
- 使用线程池可以避免频繁地创建和销毁线程,从而提高程序的性能和响应速度。
ExecutorService
提供了对线程池的统一管理和控制接口。
- 任务:
- 任务通常指的是需要并发执行的操作或计算。
- 在
ExecutorService
中,任务可以是实现了Runnable
接口或Callable
接口的对象。 Runnable
任务不返回结果,而Callable
任务可以返回结果,并且可能抛出异常。
- 提交任务:
- 通过
ExecutorService
的execute(Runnable command)
方法可以提交一个Runnable
任务。 - 通过
submit(Callable<T> task)
或submit(Runnable task, T result)
方法可以提交一个Callable
任务,并获得一个表示异步计算结果的Future
对象。
- 通过
- Future:
Future
用于表示异步计算的结果。它是ExecutorService
提交Callable
任务后返回的对象。- 通过
Future
对象,可以检查计算是否完成,等待计算完成,并获取计算结果。 - 如果计算尚未完成,
get()
方法会阻塞直到它完成。
- 关闭线程池:
- 使用完
ExecutorService
后,应该调用其shutdown()
方法来启动线程池的关闭序列。 shutdown()
方法不会立即停止线程池,而是等待已提交的任务执行完毕后才关闭。- 如果需要立即停止所有任务并关闭线程池,可以调用
shutdownNow()
方法。
- 使用完
- 任务调度:
ExecutorService
提供了对任务调度的控制,包括任务的执行顺序、优先级等。- 虽然 Java 标准库中的
ExecutorService
实现(如ThreadPoolExecutor
)可能不直接支持任务优先级,但可以通过自定义的RejectedExecutionHandler
和ThreadFactory
来实现更复杂的任务调度逻辑。
- 异常处理:
- 当任务执行过程中发生异常时,这些异常不会被
ExecutorService
直接处理或抛出。 - 对于
Runnable
任务,异常通常会被忽略(除非任务中的代码显式地处理它们)。 - 对于
Callable
任务,异常会被封装在ExecutionException
中,并通过Future.get()
方法抛出。
- 当任务执行过程中发生异常时,这些异常不会被
通过使用 ExecutorService
,开发者可以更灵活、高效地管理并发任务,而无需直接处理线程的创建、销毁和调度等底层细节。
示例
以下是一些ExecutorService
的常用方法:
submit(Runnable task)
: 提交一个Runnable
任务给线程池执行,并返回一个Future
对象,但这个Future
的get()
方法总是返回null
,因为Runnable
不返回结果。submit(Callable<T> task)
: 提交一个Callable
任务给线程池执行,并返回一个Future<T>
对象,这个Future
的get()
方法可以返回计算的结果。execute(Runnable command)
: 执行一个Runnable
任务。这个方法不返回Future
,你不能获取到任务的执行结果或处理可能的异常。shutdown()
: 发起线程池的关闭序列,不再接受新的任务,但已经提交的任务将继续执行。shutdownNow()
: 尝试停止所有正在执行的任务,暂停处理正在等待的任务,并返回等待执行的任务列表。isShutdown()
: 如果ExecutorService已经关闭,则返回true。isTerminated()
: 如果所有任务都已完成执行,则返回true。
当你不再需要ExecutorService
时,应该调用shutdown()
或shutdownNow()
方法来关闭它,以释放它占用的资源。
下面是一个简单的示例,展示了如何使用ExecutorService
来提交任务:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 | import java.util.concurrent.*; public class ExecutorServiceExample { public static void main(String[] args) throws InterruptedException, ExecutionException { // 创建一个固定大小的线程池 ExecutorService executorService = Executors.newFixedThreadPool( 5 ); // 提交一个Callable任务 Future<String> future = executorService.submit( new Callable<String>() { @Override public String call() throws Exception { // 模拟耗时任务 Thread.sleep( 2000 ); return "Hello from Callable" ; } }); // 获取Callable任务的结果 String result = future.get(); System.out.println(result); // 提交一个Runnable任务 executorService.submit( new Runnable() { @Override public void run() { // 模拟耗时任务 try { Thread.sleep( 1000 ); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println( "Hello from Runnable" ); } }); // 关闭线程池 executorService.shutdown(); // 等待线程池中的任务全部完成 if (!executorService.awaitTermination( 60 , TimeUnit.SECONDS)) { executorService.shutdownNow(); } } } |
在这个示例中,我们创建了一个固定大小的线程池,并提交了一个Callable
任务和一个Runnable
任务。Callable
任务返回了一个结果,我们通过Future
对象获取了这个结果。Runnable
任务没有返回值,只是简单地打印了一条消息。最后,我们关闭了线程池,并等待所有任务完成。
注意事项
- 使用完
ExecutorService
后,应该调用shutdown()
或shutdownNow()
方法来关闭它,以释放资源。 - 如果线程池中的任务执行时间很长,或者需要处理大量任务,应该考虑使用更复杂的线程池配置和管理策略。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)
· winform 绘制太阳,地球,月球 运作规律
2019-04-30 Sitecore 8.2 扩展体验分析报告