使用 Callable + ExecutorService 创建线程的笔记

一、核心组合的作用

Callable 是带返回值的任务接口,ExecutorService 是线程池管理接口,两者结合可实现 多线程并发执行带返回值的任务,兼具线程复用(线程池优势)和结果获取(Callable 优势)的特性。

二、关键组件

  1. **Callable<V>**:

    • 泛型接口,V 为返回值类型。
    • 需重写 call() 方法(任务执行体),支持返回结果和声明异常。
  2. **ExecutorService**:

    • 线程池接口,负责管理线程生命周期和任务调度。
    • 通过 submit(Callable<V>) 方法提交任务,返回 Future<V> 对象。
  3. **Future<V>**:

    • 用于跟踪任务状态,获取 call() 方法的返回值(get() 方法),支持取消任务(cancel())。

三、使用步骤(代码示例)

示例 1:单任务提交与结果获取
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
import java.util.concurrent.*;

public class CallableExecutorDemo {
public static void main(String[] args) throws Exception {
// 1. 创建线程池(此处用固定大小线程池,核心线程数2)
ExecutorService threadPool = Executors.newFixedThreadPool(2);

// 2. 创建Callable任务(计算1~100的和)
Callable<Integer> task = () -> {
int sum = 0;
for (int i = 1; i <= 100; i++) {
sum += i;
}
System.out.println("任务执行线程:" + Thread.currentThread().getName());
return sum; // 返回计算结果
};

// 3. 提交任务到线程池,获取Future对象(绑定任务结果)
Future<Integer> future = threadPool.submit(task);

// 4. 阻塞获取结果(等待任务完成)
int result = future.get();
System.out.println("1~100的和:" + result); // 输出:5050

// 5. 关闭线程池(必须手动关闭,否则程序不退出)
threadPool.shutdown();
}
}
示例 2:多任务并发提交与批量获取结果
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
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.*;

public class MultiCallableDemo {
public static void main(String[] args) throws Exception {
// 1. 创建线程池(核心线程数3)
ExecutorService threadPool = Executors.newFixedThreadPool(3);

// 2. 创建多个Callable任务(计算不同范围的和)
List<Callable<Integer>> tasks = new ArrayList<>();
tasks.add(() -> calculateSum(1, 100)); // 任务1:1~100
tasks.add(() -> calculateSum(101, 200)); // 任务2:101~200
tasks.add(() -> calculateSum(201, 300)); // 任务3:201~300

// 3. 批量提交任务,获取所有Future
List<Future<Integer>> futures = threadPool.invokeAll(tasks);

// 4. 遍历Future,获取每个任务的结果
int total = 0;
for (Future<Integer> future : futures) {
total += future.get(); // 累加每个任务的结果
}
System.out.println("总和:" + total); // 输出:(5050 + 15050 + 25050) = 45150

// 5. 关闭线程池
threadPool.shutdown();
}

// 工具方法:计算start到end的和
private static int calculateSum(int start, int end) {
int sum = 0;
for (int i = start; i <= end; i++) {
sum += i;
}
System.out.println(Thread.currentThread().getName() + " 计算:" + start + "~" + end + " 的和为:" + sum);
return sum;
}
}

四、核心特点

  1. 带返回值的并发任务:相比 RunnableCallable 可通过 Future.get() 获取任务结果,满足需要异步计算并返回结果的场景(如多任务并行计算后汇总)。
  2. 线程复用:通过 ExecutorService 线程池管理线程,避免频繁创建 / 销毁线程的性能开销。
  3. 异常处理call() 方法声明的异常会被 Future 捕获,调用 get() 时需处理 ExecutionException(包装任务异常)。
  4. 阻塞获取结果future.get() 会阻塞当前线程,直到任务完成;也可通过 future.isDone() 先判断任务是否完成,避免不必要的阻塞。

五、注意事项

  1. 线程池关闭:任务执行完毕后必须调用 shutdown() 关闭线程池,否则核心线程会一直存活,导致程序无法退出。
  2. 批量任务处理:使用 invokeAll(tasks) 可批量提交任务,返回所有 Future 的列表,适合需要等待所有任务完成后汇总结果的场景。
  3. 任务取消:若需取消未执行的任务,可调用 future.cancel(true)true 表示中断正在执行的任务)。

六、总结

Callable + ExecutorService 是多线程并发处理带返回值任务的最佳实践:

  • Callable 定义有返回值的任务逻辑;
  • ExecutorService 提供线程池管理,高效执行任务;
  • Future 跟踪任务状态并获取结果。

适用于并行计算、异步查询、多任务结果汇总等场景,兼顾性能与灵活性。