多线程-Future

93 阅读4分钟

背景

上一篇文章,我们讲了多线程怎么获取返回结果:使用Callable,而不是Runnable。

但是,不管是使用Callable,还是使用Runnable,这两个接口都是任务接口,具体使用的时候是,把任务线程放到线程池里去提交,只不过呢,唯一的区别就是刚才说了,一个可以获取到返回结果,一个不能。

那Callable是怎么获取到返回结果的呢?线程池提交任务之后,就可以获取到返回结果。具体来讲的话,是先返回一个Future对象,然后呢,再基于这个Future去获取返回数据。

demo

下面是一个简单的示例,演示了如何使用CallableExecutorService来执行一个可返回结果的任务:

import java.util.concurrent.*;

public class CallableExample {
    public static void main(String[] args) throws InterruptedException, ExecutionException {
        ExecutorService executorService = Executors.newSingleThreadExecutor();

        Callable<Integer> task = () -> {
            // 在这里执行耗时操作
            Thread.sleep(2000);
            return 42;
        };

        Future<Integer> future = executorService.submit(task);

        // 这里可以做一些其他的工作

        // 获取任务执行结果,如果任务还未完成,会阻塞当前线程直到完成
        int result = future.get();
        System.out.println("任务结果:" + result);

        executorService.shutdown();
    }
}

小结

从这个demo代码可以看到,说白了,想要获取返回结果,有两个点,第一个点是使用新的任务接口Callable,第二个点是使用Future,二者结合,就可以获取返回结果。

官方文档-Future

public interface Future<V>

Future represents the result of an asynchronous computation. Methods are provided to check if the computation is complete, to wait for its completion, and to retrieve the result of the computation. The result can only be retrieved using method get when the computation has completed, blocking if necessary until it is ready. Cancellation is performed by the cancel method. Additional methods are provided to determine if the task completed normally or was cancelled. Once a computation has completed, the computation cannot be cancelled. If you would like to use a Future for the sake of cancellability but not provide a usable result, you can declare types of the form Future<?> and return null as a result of the underlying task.
Future 表示异步计算的结果。提供了方法来检查计算是否完成、等待计算完成以及检索计算结果。仅当计算完成时才能使用方法 get 检索结果,必要时会阻塞,直到准备好为止。取消是通过 cancel 方法执行的。提供了其他方法来确定任务是否正常完成或已取消。一旦计算完成,就无法取消计算。如果您想使用 Future 来取消,但不提供可用的结果,您可以声明 Future<?> 形式的类型并将 null 返回为基本任务的结果。

Sample Usage (Note that the following classes are all made-up.)
用法示例(请注意,以下类都是虚构的。)

 
 interface ArchiveSearcher { String search(String target); }
 class App {
   ExecutorService executor = ...
   ArchiveSearcher searcher = ...
   void showSearch(final String target)
       throws InterruptedException {
     Future<String> future
       = executor.submit(new Callable<String>() {
         public String call() {
             return searcher.search(target);
         }});
     displayOtherThings(); // do other things while searching
     try {
       displayText(future.get()); // use future
     } catch (ExecutionException ex) { cleanup(); return; }
   }
 }

The FutureTask class is an implementation of Future that implements Runnable, and so may be executed by an Executor. For example, the above construction with submit could be replaced by:
FutureTask 类是实现 Runnable 的 Future 的实现,因此可以由 Executor 执行。例如,上面的 submit 结构可以替换为:

 
 FutureTask<String> future =
   new FutureTask<String>(new Callable<String>() {
     public String call() {
       return searcher.search(target);
   }});
 executor.execute(future);

Memory consistency effects: Actions taken by the asynchronous computation happen-before actions following the corresponding Future.get() in another thread.
内存一致性效果:异步计算所采取的操作发生在另一个线程中相应的 Future.get() 操作之后。

Future 作用

"Future" 在编程中通常指的是一种异步编程的概念,用于表示一个尚未完成的操作或任务的结果。在 Java 编程中,有一个类叫做 java.util.concurrent.Future,它用于表示异步任务的结果。

具体来说,Future 的作用如下:

  1. 异步操作的结果存储:Future 允许你启动一个异步任务,然后在后台执行,同时你可以继续执行其他任务。Future 会存储异步任务的结果,直到你需要获取它为止。

  2. 获取异步任务结果:通过 Future,你可以随时检查异步任务是否完成,以及获取其结果。这通常是通过调用 get() 方法来实现的。如果异步任务还没有完成,get() 方法会阻塞当前线程,直到任务完成并返回结果。

  3. 取消任务:你可以使用 Future 取消尚未完成的异步任务,以避免浪费资源。

  4. 异常处理:Future 也可以用于处理异步任务中的异常。如果异步任务抛出了异常,你可以通过 Future 来捕获并处理这些异常。

  5. 等待多个任务完成:Java 8 引入了 CompletableFuture,它是 Future 的增强版,允许你更灵活地处理多个异步任务的结果,例如等待所有任务完成或等待任何一个任务完成。

总的来说,Future 在 Java 中用于管理和处理异步任务的结果,使你能够更好地控制和协调多线程编程中的任务执行。