Java线程池ExecutorService学习和使用
一、概述
Java中的 ExecutorService
是一个用于管理和控制线程的接口,它是Java并发库的一部分。ExecutorService
提供了比直接使用线程更强大的功能,使得线程管理更简单、灵活和高效。本文将详细介绍 ExecutorService
的基本概念、常用方法、配置及其在实际应用中的使用。
二、基本概念
ExecutorService
提供了一种将任务提交与任务执行分离的机制。通过使用 ExecutorService
,可以创建一个线程池,将任务提交到线程池中执行,而不必手动管理线程的创建和销毁。
三、常用方法
ExecutorService
接口提供了多种方法来管理线程和任务。以下是一些常用方法:
提交任务:
submit(Runnable task)
: 提交一个Runnable任务,返回一个Future对象。submit(Callable<T> task)
: 提交一个Callable任务,返回一个Future对象。
关闭线程池:
shutdown()
: 启动有序关闭,之前提交的任务会继续执行,但不会接受新任务。shutdownNow()
: 试图停止所有正在执行的任务,暂停等待任务,并返回等待执行任务的列表。
获取线程池状态:
isShutdown()
: 如果线程池已关闭,则返回true。isTerminated()
: 如果线程池已终止,则返回true。
批量提交任务:
invokeAll(Collection<? extends Callable<T>> tasks)
: 执行给定的任务,当所有任务完成时,返回一个包含其状态和结果的Future列表。invokeAny(Collection<? extends Callable<T>> tasks)
: 执行给定的任务,当一个任务成功完成(没有抛出异常)时,返回该任务的结果。
四、线程池的创建
Java并发库提供了一些工厂方法来创建不同类型的线程池:
固定大小线程池:
ExecutorService fixedThreadPool = Executors.newFixedThreadPool(5);
单线程线程池:
ExecutorService singleThreadExecutor = Executors.newSingleThreadExecutor();
可缓存线程池:
ExecutorService cachedThreadPool = Executors.newCachedThreadPool();
定时线程池:
ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(5);
五、使用示例
以下是一个使用 ExecutorService
的示例,展示了如何提交任务和处理结果。
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();
}
}
六、线程池配置
配置线程池参数可以更好地控制其行为,以满足不同的应用需求。以下是一些常见配置:
核心线程数和最大线程数:
ThreadPoolExecutor executor = new ThreadPoolExecutor( 2, // corePoolSize 5, // maximumPoolSize 60, // keepAliveTime TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>() // workQueue );
自定义拒绝策略:
ThreadPoolExecutor executor = new ThreadPoolExecutor( 2, 5, 60, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>(), new ThreadPoolExecutor.AbortPolicy() // 默认策略,抛出RejectedExecutionException );
- 钩子函数:
可以重写ThreadPoolExecutor
的beforeExecute
和afterExecute
方法来添加钩子函数,以便在任务执行前后进行额外操作。
七、实战示例
示例1:使用ScheduledExecutorService进行定时任务调度
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:使用线程池执行大量任务并等待其完成
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();
}
}
思维导图
+------------------------------------------------------+
| Java线程池ExecutorService学习和使用 |
+------------------------------------------------------+
|
+-----------------------------+
| 一、概述 |
+-----------------------------+
|
+-----------------------------+
| 二、基本概念 |
+-----------------------------+
|
+-----------------------------+
| 三、常用方法 |
| 1. 提交任务 |
| 2. 关闭线程池 |
| 3. 获取线程池状态 |
| 4. 批量提交任务 |
+-----------------------------+
|
+-----------------------------+
| 四、线程池的创建 |
| 1. 固定大小线程池 |
| 2. 单线程线程池 |
| 3. 可缓存线程池 |
| 4. 定时线程池 |
+-----------------------------+
|
+-----------------------------+
| 五、使用示例 |
+-----------------------------+
|
+-----------------------------+
| 六、线程池配置 |
| 1. 核心线程数和最大线程数 |
| 2. 自定义拒绝策略 |
| 3. 钩子函数 |
+-----------------------------+
|
+-----------------------------+
| 七、实战示例 |
| 示例1:定时任务调度 |
| 示例2:执行大量任务并等待完成|
+-----------------------------+
总结
通过学习和使用Java中的 ExecutorService
,可以显著提升并发编程的效率和代码的可维护性。合理配置线程池参数,结合实际应用场景,可以实现高效、可靠的并发处理。希望本文提供的示例和思路能够帮助开发者深入理解并应用 ExecutorService
,实现更高效的并发程序。