返回

剖析 FutureTask:JUC 源码深入浅出

见解分享

在 Java 并发编程的浩瀚世界中,FutureTask 扮演着举足轻重的角色。作为 Callable 和 Future 的完美结合,它为异步编程提供了优雅而强大的解决方案。本文将带你踏上 FutureTask 的探索之旅,深入剖析它的源码,揭开 Java 并发编程的精妙之处。

FutureTask 的核心职责

FutureTask 同时实现了 Callable 和 Future 接口,巧妙地将任务的执行和结果的获取融为一体。它负责以下关键任务:

  • 执行 Callable 任务: FutureTask 充当 Callable 的执行器,调用 Callable.call() 方法来执行任务。
  • 存储任务结果: 任务执行完毕后,结果将被存储在 FutureTask 的 outcome 字段中。
  • 提供 Future 接口: FutureTask 实现了 Future 接口,允许其他线程获取任务执行结果或检查其完成状态。

FutureTask 的工作原理

FutureTask 的工作原理可以概括为以下几个步骤:

  1. 任务提交: 当 FutureTask 被创建并提交给 ExecutorService 时,它会立即开始执行 Callable.call() 方法。
  2. 并发访问: 多个线程可以并发地访问 FutureTask,以获取任务执行结果或检查其完成状态。
  3. 阻塞等待: 如果任务尚未完成,线程将被阻塞,等待任务完成。
  4. 结果返回: 当任务完成时,结果将被存储在 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 并发编程的精髓。