返回
剖析 FutureTask:JUC 源码深入浅出
见解分享
2024-01-16 06:52:32
在 Java 并发编程的浩瀚世界中,FutureTask 扮演着举足轻重的角色。作为 Callable 和 Future 的完美结合,它为异步编程提供了优雅而强大的解决方案。本文将带你踏上 FutureTask 的探索之旅,深入剖析它的源码,揭开 Java 并发编程的精妙之处。
FutureTask 的核心职责
FutureTask 同时实现了 Callable 和 Future 接口,巧妙地将任务的执行和结果的获取融为一体。它负责以下关键任务:
- 执行 Callable 任务: FutureTask 充当 Callable 的执行器,调用 Callable.call() 方法来执行任务。
- 存储任务结果: 任务执行完毕后,结果将被存储在 FutureTask 的 outcome 字段中。
- 提供 Future 接口: FutureTask 实现了 Future 接口,允许其他线程获取任务执行结果或检查其完成状态。
FutureTask 的工作原理
FutureTask 的工作原理可以概括为以下几个步骤:
- 任务提交: 当 FutureTask 被创建并提交给 ExecutorService 时,它会立即开始执行 Callable.call() 方法。
- 并发访问: 多个线程可以并发地访问 FutureTask,以获取任务执行结果或检查其完成状态。
- 阻塞等待: 如果任务尚未完成,线程将被阻塞,等待任务完成。
- 结果返回: 当任务完成时,结果将被存储在 FutureTask 的 outcome 字段中,并通知所有等待的线程。
FutureTask 的内部结构
FutureTask 的内部结构包含多个关键组件:
- outcome 字段: 用于存储任务的执行结果。
- state 字段: 表示任务的当前状态(NEW、RUNNING、COMPLETED、CANCELLED)。
- waiters 队列: 存储所有等待任务完成的线程。
- WaitsNode 类: 封装了等待任务完成的线程和等待超时的时间。
剖析 FutureTask 源码
FutureTask 的源码位于 java.util.concurrent 包中。为了便于理解,我们将重点关注关键方法的实现:
set 方法:
public void set(T v) {
if (v == null)
throw new NullPointerException();
synchronized (this) {
outcome = v;
state = state.DONE();
notifyAll();
}
}
- 该方法设置任务执行结果并更新状态为完成。
- 它唤醒所有等待任务完成的线程。
get 方法:
public T get() throws InterruptedException, ExecutionException {
...
int s = state;
if (s <= COMPLETING)
s = awaitDone(s);
return report(s);
}
- 该方法等待任务完成并返回结果。
- 如果任务尚未完成,它将阻塞线程并等待。
awaitDone 方法:
private int awaitDone(int s) throws InterruptedException {
...
// 如果任务状态小于等于 COMPLETING,则循环等待任务完成
while (s <= COMPLETING) {
...
Waiter waiter = new Waiter();
waiter.awaitCheck();
// 把 Waiter 添加到 waiters 队列中
addWaiter(waiter);
try {
// 阻塞线程等待任务完成
waiter.done.await(isDone(), waiter.timeout);
} finally {
// 从 waiters 队列中移除 Waiter
if (waiter.shouldBeRemoved)
removeWaiter(waiter);
}
}
}
- 该方法阻塞线程并等待任务完成。
- 它使用 WaitNode 类来管理等待线程。
总结
FutureTask 是 Java 并发编程中至关重要的组件,它提供了优雅而强大的机制来执行异步任务和获取结果。通过深入剖析其源码,我们得以了解其内部结构和工作原理,从而进一步掌握 Java 并发编程的精髓。