Callable、Future 和 Executor:深入剖析并发编程的基础
2023-09-21 04:01:07
深入理解 Callable、Future 和 Executor:解锁 Java 并发编程的强大功能
Callable:封装异步任务
想象一个 Callable,就像一个熟练的厨师,负责执行一个特定任务,然后返回精心制作的结果。它类似于 Runnable,但与 Runnable 不同的是,它在完成任务后会返回一个结果,就像厨师精心制作的菜肴。
Future:获取任务结果
Future 就好像一位耐心等待的侍者,它持有任务的结果,直到厨师准备好。它提供了一个 get() 方法,就像一位顾客要求上菜一样,Future 会阻塞并等待厨师完成任务,然后将结果呈上。
Executor:任务执行的指挥官
Executor 就像一位经验丰富的餐厅经理,它负责管理厨师(任务)和资源(线程)。当一个任务准备好被执行时,经理就会将其交给一个厨师(线程),厨师负责执行任务并返回结果。
构建我们自己的工具
为了真正理解这些概念,让我们亲自动手构建它们。
Callable:任务的蓝图
public class SumTask implements Callable<Integer> {
private List<Integer> numbers;
public SumTask(List<Integer> numbers) {
this.numbers = numbers;
}
@Override
public Integer call() {
int sum = 0;
for (int num : numbers) {
sum += num;
}
return sum;
}
}
Future:结果的容器
public class SumFuture implements Future<Integer> {
private Integer result;
private boolean isDone;
public Integer get() {
while (!isDone) {
try {
wait();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
return result;
}
public boolean isDone() {
return isDone;
}
public boolean cancel(boolean mayInterruptIfRunning) {
return false;
}
public void setResult(Integer result) {
synchronized (this) {
this.result = result;
this.isDone = true;
notifyAll();
}
}
}
Executor:任务的执行者
public class SimpleExecutor implements Executor {
@Override
public void execute(Runnable command) {
new Thread(command).start();
}
}
使用我们的工具
现在,我们有了自己的工具,让我们执行一个异步任务:
List<Integer> numbers = List.of(1, 2, 3, 4, 5);
SumTask task = new SumTask(numbers);
SumFuture future = new SumFuture();
SimpleExecutor executor = new SimpleExecutor();
executor.execute(task);
Integer result = future.get();
System.out.println("Sum of numbers: " + result);
这个代码就像一个精心编排的交响乐。厨师(task)负责计算数字的总和,然后将结果交给服务员(future),由服务员将其交给顾客(main 线程)。
常见问题解答
1. Callable 和 Runnable 有什么区别?
Callable 返回一个结果,而 Runnable 则没有。
2. Future 和 synchronized 有什么关系?
Future 使用 synchronized 关键字来确保线程安全和结果的正确性。
3. Executor 有哪些不同类型?
有单线程、固定线程池和缓存线程池等类型的 Executor。
4. 如何处理异常?
Future 会传播由任务引发的异常。
5. 如何取消任务?
Future 提供了一个 cancel() 方法,但在我们自己的实现中,它已被禁用。