ExecutorService 是 Java 中一个用于管理线程池和并发任务执行的框架。它是 java.util.concurrent 包的一部分。ExecutorService 提供了一种比使用 Thread 类更方便和灵活的方式来管理线程。
1. 基本概念
1.1 Executor 和 ExecutorService
- Executor:定义了一个 execute(Runnable command) 方法,用来执行提交的 Runnable 任务。
- ExecutorService:继承了 Executor,提供了更多方法来管理和控制任务的执行,如 submit、shutdown、invokeAll 等。
1.2 线程池类型
- FixedThreadPool:定长线程池,可以控制线程最大并发数,多余的线程会在队列中等待。
- CachedThreadPool:可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程。
- SingleThreadExecutor:单线程池,只有一个线程工作,确保所有任务按照指定顺序(FIFO, LIFO, 优先级)执行。
- ScheduledThreadPool:定时线程池,用于执行定时任务或周期性任务。
2. 常用方法
2.1 任务提交方法
- execute(Runnable command):执行一个 Runnable 任务,但无返回值。
- submit(Runnable task):执行一个 Runnable 任务,并返回一个 Future 对象,可以通过 Future 对象获取任务的执行结果。
- submit(Callable<T> task):执行一个 Callable 任务,并返回一个 Future 对象,Callable 有返回值。
2.2 任务调度方法(ScheduledExecutorService)
- schedule(Runnable command, long delay, TimeUnit unit):延迟执行任务。
- schedule(Callable<V> callable, long delay, TimeUnit unit):延迟执行任务并获取结果。
- scheduleAtFixedRate(Runnable command, long initialDelay, long period, TimeUnit unit):周期性执行任务,以固定频率执行。
- scheduleWithFixedDelay(Runnable command, long initialDelay, long delay, TimeUnit unit):周期性执行任务,以固定延迟执行。
2.3 关闭线程池
- shutdown():启动一次顺序关闭,执行以前提交的任务,但不接受新任务。
- shutdownNow():试图停止所有正在执行的任务,暂停处理等待的任务,并返回等待执行的任务列表。
3. 使用示例
3.1 基本线程池示例
有5个任务需要执行。
使用一个固定大小为3的线程池来并发执行这些任务。
每个任务执行的过程包括打印任务开始的信息、模拟执行2秒、打印任务完成的信息。
线程池中有3个线程 (pool-1-thread-1、pool-1-thread-2 和 pool-1-thread-3),每个线程可以同时执行一个任务。
前3个任务会立即被分配给线程池中的3个线程并开始执行。
每个任务执行2秒,然后完成,接着线程池中的线程会继续执行等待中的任务。
最终,所有任务都完成执行。
3.2 使用 Callable 和 Future
如果需要每个任务执行之后需要返回一个结果,可以实现Callable接口并重写call方法
- 使用 Callable 接口和 Future 对象可以提交有返回值的任务,并获取任务执行结果。
- ExecutorService 提供了管理线程池和并发任务执行的能力。
- submit 方法用于提交 Callable 任务,Future 对象用于获取任务的结果或状态。
- 通过 future.get() 方法可以阻塞等待任务执行完成并获取结果。
3.3 使用 ScheduledExecutorService 调度任务
4. 更多高级用法
4.1 使用 invokeAll 和 invokeAny
- invokeAll:批量提交任务,并等待所有任务完成,返回所有任务的结果。
- invokeAny:批量提交任务,并返回最先完成任务的结果。