欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Future,你只需看这一篇就够了

程序员文章站 2022-06-05 19:50:21
...

如题:最近在读组内kafka项目的代码,看到有关future的用法, 总结一下。

Future主要是用于获取线程执行任务结果

Java通过ThreadPoolExecutor中的3个Submit方法,和一个FutureTask工具类来获取线程任务执行结果。这三个submit的方法签名如下:

// 提交 Runnable 任务
Future<?> submit(Runnable task);
// 提交 Callable 任务
<T> Future<T> submit(Callable<T> task);
// 提交 Runnable 任务及结果引用  
<T> Future<T> submit(Runnable task, T result);

下面简单介绍一下这三个方法:

1 方法1的参数是Runnable,这个对象中的run方法是没有返回值的,所以我们通过它只能判断任务是否执行完毕

2 方法2的参数是Callable,这个对象中的call方法是有返回值的,所以可以通过future中的get方法来获取任务执行的返回值

3 方法3比较特殊,其中的result是主线程和工作线程的桥梁,我们可以将task中的的执行结果存储在result中,下面的示例代码简述了它的用法:

ExecutorService executor = Executors.newFixedThreadPool(1);

Result r = new Result();
r.setAAA(a);
// 提交任务
Future<Result> future = executor.submit(new Task(r), r);  
Result fr = future.get();
// 下面等式成立
fr === r;
fr.getAAA() === a;
fr.getXXX() === x

class Task implements Runnable{
  Result r;
  // 通过构造函数传入 result
  Task(Result r){
    this.r = r;
  }
  void run() {
    // 可以操作 result
    a = r.getAAA();
    r.setXXX(x);
  }
}

Future的核心方法有5个,方法签名如下:

// 取消任务
boolean cancel(boolean mayInterruptIfRunning);
// 判断任务是否已取消  
boolean isCancelled();
// 判断任务是否已结束
boolean isDone();
// 获得任务执行结果
get();
// 获得任务执行结果,支持超时
get(long timeout, TimeUnit unit);

值得注意的是,get方法是阻塞方法, 建议使用带有超时时间的get方法。

学会了Future和Runnable的用法,那么再去理解FutureTask就会容易很多,因为Future其实就是实现了Runnable和Future的工具类,所以它既可以作为一个Task,被线程执行,又因为它实现了Future接口,所以它也可以用来获取任务执行结果。

public class FutureTask<V> implements RunnableFuture<V>

public interface RunnableFuture<V> extends Runnable, Future<V> {
    /**
     * Sets this Future to the result of its computation
     * unless it has been cancelled.
     */
    void run();
}

它的构造方法如下:

FutureTask(Callable<V> callable);
FutureTask(Runnable runnable, V result);

使用FutureTask的示例代码如下:

// 创建 FutureTask
FutureTask<Integer> futureTask = new FutureTask<>(()-> 1+2);
// 创建线程池
ExecutorService es = Executors.newCachedThreadPool();
// 提交 FutureTask 
es.submit(futureTask);
// 获取计算结果
Integer result = futureTask.get();

直接使用FutureTask执行的案例:

// 创建 FutureTask 
FutureTask<Integer> futureTask = new FutureTask<>(()-> 1+2);
// 创建并启动线程
new Thread(futureTask).start();
// 获取计算结果
Integer result = futureTask.get();