目录

hymn

忽有故人心头过,回首山河已是秋。

X

使用Future 和 CompletableFuture

Future
ExecutorService executor = Executors.newFixedThreadPool(4); 
// 定义任务:
Callable<String> task = new Task();
// 提交任务并获得Future:
Future<String> future = executor.submit(task);
// 从Future获取异步执行返回的结果:
String result = future.get(); // 可能阻塞

当我们提交一个 Callable任务后,我们会同时获得一个 Future对象,然后,我们在主线程某个时刻调用 Future对象的 get()方法,就可以获得异步执行的结果。在调用 get()时,如果异步任务已经完成,我们就直接获得结果。如果异步任务还没有完成,那么 get()会阻塞,直到任务完成后才返回结果。

一个 Future<V>接口表示一个未来可能会返回的结果,它定义的方法有:

  • get():获取结果(可能会等待)
  • get(long timeout, TimeUnit unit):获取结果,但只等待指定的时间;
  • cancel(boolean mayInterruptIfRunning):取消当前任务;
  • isDone():判断任务是否已完成。

小结

对线程池提交一个 Callable任务,可以获得一个 Future对象;

可以用 Future在将来某个时刻获取结果。

CompletableFuture

使用 Future获得异步执行结果时,要么调用阻塞方法 get(),要么轮询看 isDone()是否为 true,这两种方法都不是很好,因为主线程也会被迫等待。

从Java 8开始引入了 CompletableFuture,它针对 Future做了改进,可以传入回调对象,当异步任务完成或者发生异常时,自动调用回调对象的回调方法。

public class Main {
    public static void main(String[] args) throws Exception {
        // 创建异步执行任务:
        CompletableFuture<Double> cf = CompletableFuture.supplyAsync(Main::fetchPrice);
        // 如果执行成功:
        cf.thenAccept((result) -> {
            System.out.println("price: " + result);
        });
        // 如果执行异常:
        cf.exceptionally((e) -> {
            e.printStackTrace();
            return null;
        });
        // 主线程不要立刻结束,否则CompletableFuture默认使用的线程池会立刻关闭:
        Thread.sleep(200);
    }

    static Double fetchPrice() {
        try {
            Thread.sleep(100);
        } catch (InterruptedException e) {
        }
        if (Math.random() < 0.3) {
            throw new RuntimeException("fetch price failed!");
        }
        return 5 + Math.random() * 20;
    }
}

CompletableFuture可以指定异步处理流程:

  • thenAccept()处理正常结果;
  • exceptional()处理异常结果;
  • thenApplyAsync()用于串行化另一个CompletableFuture
  • anyOf()allOf()用于并行化多个CompletableFuture

标题:使用Future 和 CompletableFuture
作者:hymn
地址:https://dxyhymn.com/articles/2020/12/04/1607073934695.html