Future和 FutureTask

Future和 FutureTask

FutureFutureTask 在Java并发编程中扮演着重要的角色,它们主要用于异步计算的结果。尽管它们都与异步任务的执行和结果的处理有关,但它们之间还是有一些区别的。

Future

Future 是一个接口,它提供了检查计算是否完成、等待计算完成以及检索计算结果的方法。它通常与 ExecutorService 一起使用,以异步方式执行任务。Future 允许你启动一个可能耗时的计算,而不必等待它完成就能继续执行其他任务。然后,你可以使用 Future 对象来查询计算是否完成,等待计算完成,并检索计算的结果。

主要的方法包括:

  • boolean isDone():如果任务完成,则返回 true
  • boolean isCancelled():如果任务被取消,则返回 true
  • V get():等待任务完成,然后获取其结果。
  • V get(long timeout, TimeUnit unit):等待任务在给定的时间范围内完成,并获取其结果。
  • boolean cancel(boolean mayInterruptIfRunning):尝试取消任务的执行。

FutureTask

FutureTaskFuture 接口的一个实现类,它实现了 RunnableFuture 接口。它可以将一个 Callable(可以返回结果的 Runnable)或 Runnable 任务包装成一个 Future 任务。FutureTask 主要用于异步计算,并且它可以让你将计算的结果存储在一个 Future 对象中,以便后续可以查询和获取这个结果。

FutureTask 提供了对启动和取消异步计算的支持,以及查询计算是否完成和检索计算结果的方法。此外,FutureTask 还可以作为一个 Runnable 对象被提交给 Executor 执行,这意呀着你可以将 FutureTask 提交给 ExecutorService 来异步执行。

主要区别

  • 实现与接口Future 是一个接口,而 FutureTaskFuture 接口的一个具体实现。
  • 功能Future 主要定义了异步计算结果的获取方法,而 FutureTask 除了这些功能外,还实现了 Runnable 接口,因此可以直接提交给 Executor 执行。
  • 使用场景:当你只需要一个 Future 功能的引用时(比如,你已经有了一个 Future 类型的变量,但你不想或不需要知道具体的实现),你会使用 Future。而当你需要提交一个可返回结果的异步任务给 Executor 执行时,你会使用 FutureTask

示例

使用 FutureTask 提交任务给 ExecutorService 的示例:

ExecutorService executor = Executors.newSingleThreadExecutor();
Callable<Integer> task = () -> {
    // 模拟耗时任务
    TimeUnit.SECONDS.sleep(1);
    return 123;
};

FutureTask<Integer> futureTask = new FutureTask<>(task);
executor.submit(futureTask);

// ... 可以执行其他任务

try {
    // 等待任务完成并获取结果
    Integer result = futureTask.get();
    System.out.println("Result: " + result);
} catch (InterruptedException | ExecutionException e) {
    e.printStackTrace();
}

executor.shutdown();

在这个示例中,我们创建了一个 Callable 任务,并将其包装在 FutureTask 中,然后提交给 ExecutorService 异步执行。最后,我们使用 futureTask.get() 方法等待任务完成并获取结果。

与 ExecutorService 一起使用的示例代码

确实,FutureTask 通常与 ExecutorService 一起使用来实现异步计算。以下是一个使用 FutureTaskExecutorService 的示例代码,该代码展示了如何提交一个异步任务,并在需要时获取其结果。

import java.util.concurrent.*;

public class FutureTaskExample {

    public static void main(String[] args) {
        // 创建一个ExecutorService,这里使用固定大小的线程池
        ExecutorService executor = Executors.newFixedThreadPool(2);

        // 创建一个Callable任务,它将在未来某个时间点由ExecutorService执行
        Callable<String> task = () -> {
            // 模拟耗时操作
            TimeUnit.SECONDS.sleep(2);
            return "Hello from FutureTask";
        };

        // 将Callable任务包装在FutureTask中
        // 注意:这里我们实际上可以直接将Callable提交给executor.submit(),它会自动返回一个Future<?>,但为了演示FutureTask,我们显式地创建它
        FutureTask<String> futureTask = new FutureTask<>(task);

        // 提交FutureTask给ExecutorService执行
        // 注意:由于FutureTask实现了Runnable接口,我们可以直接提交它
        executor.submit(futureTask);

        // 在这里,你可以执行其他任务,而不需要等待上面的任务完成

        // ... 其他代码 ...

        // 当你需要上面任务的结果时,可以调用futureTask.get()来等待结果
        try {
            // get()方法会阻塞当前线程,直到任务完成并返回结果
            String result = futureTask.get();
            System.out.println("Result from FutureTask: " + result);
        } catch (InterruptedException | ExecutionException e) {
            // 处理异常
            e.printStackTrace();
        }

        // 关闭ExecutorService,不再接受新任务,并且等待所有已提交的任务完成
        executor.shutdown();

        // 如果你想立即停止所有正在执行的任务,并尝试停止等待执行的任务,可以使用shutdownNow()
        // 但请注意,shutdownNow()并不保证能停止所有正在执行的任务
        // executor.shutdownNow();
    }
}

在这个示例中,我们创建了一个 ExecutorService,它是一个固定大小的线程池。然后,我们定义了一个 Callable 任务,该任务在执行时会模拟一个耗时操作(例如,通过 TimeUnit.SECONDS.sleep(2); 暂停2秒)。我们将这个 Callable 任务包装在 FutureTask 中,并将其提交给 ExecutorService 执行。

由于 FutureTask 实现了 Runnable 接口,我们可以直接将它提交给 ExecutorService。然而,提交 Callableexecutor.submit(Callable<T> task) 方法也会返回一个 Future<T>,这实际上是 FutureTask 的一个实例(或者至少其行为与 FutureTask 类似)。但在这个示例中,我们为了展示 FutureTask 的用法而显式地创建了它。

最后,我们通过调用 futureTask.get() 方法来等待任务完成并获取其结果。如果任务尚未完成,get() 方法将阻塞调用它的线程,直到任务完成。一旦任务完成,get() 方法将返回任务的结果。

请注意,在实际应用程序中,你应该在不再需要 ExecutorService 时调用 shutdown() 方法来关闭它,以释放其资源。如果你需要立即停止所有正在执行的任务(尽管这通常不是一个好主意,因为它可能会导致数据不一致等问题),你可以调用 shutdownNow() 方法。但是,请注意 shutdownNow() 方法并不保证能够停止所有正在执行的任务。

未完待续(Sync的状态、运行、取消、获取数据、Sync和AQS)

  • 24
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值