文章目录
1. 并发工具类简介
1.1 ExecutorService
- 作用:
ExecutorService 是 Java 并发包中一个用于管理线程池的接口,封装了线程的创建、执行和销毁过程。 - 特点:
1.能动态分配线程资源;
2.能安排任务的执行,并且支持有返回结果的任务;
3.提供 shutdown()/shutdownNow() 方法用于平滑关闭线程池。
1.2 Callable 和 Future
- Callable 接口:
与 Runnable 接口类似,不同点在于 Callable 可以返回任务执行结果,并且可以抛出异常。其定义一个泛型方法call()。 - Future 接口:
Future 表示异步计算的结果,提供了方法来检查任务是否完成、获取结果以及取消任务等。- 通过
get()方法可以阻塞等待任务完成并返回结果。 - 通过
cancel()方法可以取消任务执行。
- 通过
1.3 Executors 工具类
- 作用:
Executors 是一个工具类,提供了一系列静态方法简化线程池的创建,如:Executors.newFixedThreadPool(n):创建一个固定大小的线程池。Executors.newCachedThreadPool():创建一个可缓存的线程池,适合执行大量短生命周期任务。Executors.newSingleThreadExecutor():创建一个只有一个线程的线程池,按顺序执行任务。
1.4 线程池优势
- 资源复用:线程池维护一定数量的线程,可重复利用这些线程,避免了频繁创建和销毁线程带来的开销。
- 任务调度:线程池内部提供任务队列管理,支持任务的延迟执行和周期性执行。
- 更好的控制:可通过线程池参数控制线程的最大并发数、任务等待队列大小,从而有效管理系统资源并避免系统过载。
2. 实践:线程池执行任务并收集结果示例
接下来我们编写一个示例程序。程序步骤如下:
1.创建一个固定大小的线程池(例如 3 个线程)。
2.提交一组 Callable 任务,每个任务返回一个计算结果(比如对任务编号进行简单运算或拼接字符串)。
3.使用 Future 收集任务的返回结果。
4.输出任务的执行结果。
5.最后平滑地关闭线程池。
2.1 示例代码
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
public class ThreadPoolExample {
public static void main(String[] args) {
// 1. 创建固定大小为3的线程池
ExecutorService executor = Executors.newFixedThreadPool(3);
// 2. 创建一个任务列表(Callable任务)
List<Callable<String>> taskList = new ArrayList<>();
// 假设我们提交5个任务,每个任务返回一个字符串结果
for (int i = 1; i <= 5; i++) {
final int taskId = i;
taskList.add(new Callable<String>() {
@Override
public String call() throws Exception {
// 模拟任务耗时
Thread.sleep(500);
return "任务 " + taskId + " 执行完毕";
}
});
}
try {
// 3. 执行所有任务,并返回一个包含 Future 对象的列表
List<Future<String>> futureList = executor.invokeAll(taskList);
// 4. 逐个获取任务返回结果(Future.get()会阻塞直到任务完成)
for (Future<String> future : futureList) {
try {
String result = future.get();
System.out.println("任务返回结果:" + result);
} catch (InterruptedException | ExecutionException e) {
System.err.println("任务执行异常:" + e.getMessage());
}
}
} catch (InterruptedException e) {
System.err.println("任务提交过程中被中断:" + e.getMessage());
} finally {
// 5. 关闭线程池
executor.shutdown();
}
}
}
3. 代码详解
3.1 线程池的创建
ExecutorService executor = Executors.newFixedThreadPool(3);
- 使用
Executors.newFixedThreadPool(3)创建一个固定大小为 3 的线程池。这样,线程池中最多同时运行 3 个线程。
3.2 定义任务列表
List<Callable<String>> taskList = new ArrayList<>();
- 使用
Callable<String>表明任务返回的是一个 String 类型的结果。 - 循环提交 5 个任务,每个任务模拟了 500 毫秒的工作,并返回 “任务 i 执行完毕”。
3.3 提交任务并收集 Future
List<Future<String>> futureList = executor.invokeAll(taskList);
invokeAll方法接受任务列表,并一次性提交所有任务到线程池中,会阻塞直到所有任务完成。- 返回一个 Future 列表,未来可以用来获取每个任务的执行结果。
3.4 获取任务执行结果
for (Future<String> future : futureList) {
String result = future.get();
System.out.println("任务返回结果:" + result);
}
- 遍历 Future 列表,对于每个任务调用
future.get(),该方法会阻塞直到任务完成并返回结果。 - 输出结果显示每个任务的返回字符串。
3.5 关闭线程池
executor.shutdown();
- 调用
shutdown()方法,线程池不再接受新的任务,并等待已提交的任务执行完毕后关闭。
4. 编译与运行结果
4.1 编译
在你的 IDE(如 IntelliJ IDEA)中创建一个 Java 类 ThreadPoolExample.java,粘贴上述代码,然后编译整个项目。
4.2 运行结果
运行程序后,控制台的输出类似如下:
任务返回结果:任务 1 执行完毕
任务返回结果:任务 2 执行完毕
任务返回结果:任务 3 执行完毕
任务返回结果:任务 4 执行完毕
任务返回结果:任务 5 执行完毕
说明:
- 输出结果的顺序可能与任务提交的顺序一致,因为
invokeAll会按照任务列表顺序返回 Future,即使内部任务并发运行,因为它等待所有任务完成后才返回。 - 每个任务的执行结果是由任务内部返回字符串确定的,模拟了耗时计算,并验证了线程池任务的并行处理能力。
5. 总结
- ExecutorService 与线程池:
使用线程池可以避免频繁创建和销毁线程,通过合理配置线程池大小来复用线程,提高性能并控制资源使用。 - Callable 与 Future:
Callable 能返回结果,Future 用来获取这些结果和检测任务状态,是执行有返回结果任务的首选方式。 - 使用 Executors 创建线程池:
Executors 工具类提供了多种线程池创建方式,简单方便地管理并发任务执行。
&spm=1001.2101.3001.5002&articleId=147165991&d=1&t=3&u=e44bbb45194a458f957f06eb95a3db2d)
1199

被折叠的 条评论
为什么被折叠?



