Loading... ### Java线程池ExecutorService学习和使用 #### 一、概述 Java中的 `ExecutorService`是一个用于管理和控制线程的接口,它是Java并发库的一部分。`ExecutorService`提供了比直接使用线程更强大的功能,使得线程管理更简单、灵活和高效。本文将详细介绍 `ExecutorService`的基本概念、常用方法、配置及其在实际应用中的使用。 ![](https://www.8kiz.cn/usr/uploads/2024/07/2472534433.png) #### 二、基本概念 `ExecutorService`提供了一种将任务提交与任务执行分离的机制。通过使用 `ExecutorService`,可以创建一个线程池,将任务提交到线程池中执行,而不必手动管理线程的创建和销毁。 #### 三、常用方法 `ExecutorService`接口提供了多种方法来管理线程和任务。以下是一些常用方法: 1. **提交任务**: - `submit(Runnable task)`: 提交一个Runnable任务,返回一个Future对象。 - `submit(Callable<T> task)`: 提交一个Callable任务,返回一个Future对象。 2. **关闭线程池**: - `shutdown()`: 启动有序关闭,之前提交的任务会继续执行,但不会接受新任务。 - `shutdownNow()`: 试图停止所有正在执行的任务,暂停等待任务,并返回等待执行任务的列表。 3. **获取线程池状态**: - `isShutdown()`: 如果线程池已关闭,则返回true。 - `isTerminated()`: 如果线程池已终止,则返回true。 4. **批量提交任务**: - `invokeAll(Collection<? extends Callable<T>> tasks)`: 执行给定的任务,当所有任务完成时,返回一个包含其状态和结果的Future列表。 - `invokeAny(Collection<? extends Callable<T>> tasks)`: 执行给定的任务,当一个任务成功完成(没有抛出异常)时,返回该任务的结果。 #### 四、线程池的创建 Java并发库提供了一些工厂方法来创建不同类型的线程池: 1. **固定大小线程池**: ```java ExecutorService fixedThreadPool = Executors.newFixedThreadPool(5); ``` 2. **单线程线程池**: ```java ExecutorService singleThreadExecutor = Executors.newSingleThreadExecutor(); ``` 3. **可缓存线程池**: ```java ExecutorService cachedThreadPool = Executors.newCachedThreadPool(); ``` 4. **定时线程池**: ```java ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(5); ``` #### 五、使用示例 以下是一个使用 `ExecutorService`的示例,展示了如何提交任务和处理结果。 ```java import java.util.concurrent.*; public class ExecutorServiceExample { public static void main(String[] args) { ExecutorService executorService = Executors.newFixedThreadPool(3); Runnable task1 = () -> { System.out.println("Executing Task1"); }; Callable<String> task2 = () -> { return "Task2 Completed"; }; executorService.submit(task1); Future<String> future = executorService.submit(task2); try { String result = future.get(); System.out.println(result); } catch (InterruptedException | ExecutionException e) { e.printStackTrace(); } executorService.shutdown(); } } ``` #### 六、线程池配置 配置线程池参数可以更好地控制其行为,以满足不同的应用需求。以下是一些常见配置: 1. **核心线程数和最大线程数**: ```java ThreadPoolExecutor executor = new ThreadPoolExecutor( 2, // corePoolSize 5, // maximumPoolSize 60, // keepAliveTime TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>() // workQueue ); ``` 2. **自定义拒绝策略**: ```java ThreadPoolExecutor executor = new ThreadPoolExecutor( 2, 5, 60, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>(), new ThreadPoolExecutor.AbortPolicy() // 默认策略,抛出RejectedExecutionException ); ``` 3. **钩子函数**: 可以重写 `ThreadPoolExecutor`的 `beforeExecute`和 `afterExecute`方法来添加钩子函数,以便在任务执行前后进行额外操作。 #### 七、实战示例 ##### 示例1:使用ScheduledExecutorService进行定时任务调度 ```java import java.util.concurrent.*; public class ScheduledExecutorServiceExample { public static void main(String[] args) { ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(2); Runnable task = () -> System.out.println("Executing Task at " + System.nanoTime()); scheduledExecutorService.scheduleAtFixedRate(task, 0, 2, TimeUnit.SECONDS); try { Thread.sleep(10000); // 让调度执行一段时间 } catch (InterruptedException e) { e.printStackTrace(); } scheduledExecutorService.shutdown(); } } ``` ##### 示例2:使用线程池执行大量任务并等待其完成 ```java import java.util.concurrent.*; public class BulkTaskExample { public static void main(String[] args) { ExecutorService executorService = Executors.newFixedThreadPool(10); Callable<String> task = () -> { TimeUnit.SECONDS.sleep(1); return Thread.currentThread().getName(); }; List<Future<String>> futures = new ArrayList<>(); for (int i = 0; i < 20; i++) { futures.add(executorService.submit(task)); } futures.forEach(future -> { try { System.out.println(future.get()); } catch (InterruptedException | ExecutionException e) { e.printStackTrace(); } }); executorService.shutdown(); } } ``` ### 思维导图 ```plaintext +------------------------------------------------------+ | Java线程池ExecutorService学习和使用 | +------------------------------------------------------+ | +-----------------------------+ | 一、概述 | +-----------------------------+ | +-----------------------------+ | 二、基本概念 | +-----------------------------+ | +-----------------------------+ | 三、常用方法 | | 1. 提交任务 | | 2. 关闭线程池 | | 3. 获取线程池状态 | | 4. 批量提交任务 | +-----------------------------+ | +-----------------------------+ | 四、线程池的创建 | | 1. 固定大小线程池 | | 2. 单线程线程池 | | 3. 可缓存线程池 | | 4. 定时线程池 | +-----------------------------+ | +-----------------------------+ | 五、使用示例 | +-----------------------------+ | +-----------------------------+ | 六、线程池配置 | | 1. 核心线程数和最大线程数 | | 2. 自定义拒绝策略 | | 3. 钩子函数 | +-----------------------------+ | +-----------------------------+ | 七、实战示例 | | 示例1:定时任务调度 | | 示例2:执行大量任务并等待完成| +-----------------------------+ ``` ### 总结 通过学习和使用Java中的 `ExecutorService`,可以显著提升并发编程的效率和代码的可维护性。合理配置线程池参数,结合实际应用场景,可以实现高效、可靠的并发处理。希望本文提供的示例和思路能够帮助开发者深入理解并应用 `ExecutorService`,实现更高效的并发程序。 最后修改:2024 年 07 月 22 日 © 允许规范转载 打赏 赞赏作者 支付宝微信 赞 如果觉得我的文章对你有用,请随意赞赏