Java多线程之CompletableFuture

2,046 阅读3分钟

CompletableFuture是JDK8提出的一个支持非阻塞的多功能的Future,同样也是实现了Future接口。

1、 runAsync 和 supplyAsync方法

public static CompletableFuture<Void> runAsync(Runnable runnable)
public static CompletableFuture<Void> runAsync(Runnable runnable, Executor executor)
public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier)
public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier, Executor executor)

没有指定Executor的方法会使用 ForkJoinPool.commonPool() 作为它的线程池执行异步代码。如果指定线程池,则使用指定的线程池运行。以下所有的方法都类同。

  • runAsync方法不支持返回值。
  • supplyAsync可以支持返回值。

2、计算结果完成时的回调方法

public CompletableFuture<T> 	whenComplete(BiConsumer<? super T,? super Throwable> action)
public CompletableFuture<T> 	whenCompleteAsync(BiConsumer<? super T,? super Throwable> action)
public CompletableFuture<T> 	whenCompleteAsync(BiConsumer<? super T,? super Throwable> action, Executor executor)
public CompletableFuture<T>     exceptionally(Function<Throwable,? extends T> fn)

上面的四种方法都返回了CompletableFuture,当我们Action执行完毕的时候,future返回的值和我们原始的CompletableFuture的值是一样的。上面以Async结尾的会在新的线程池中执行,上面没有一Async结尾的会在之前的CompletableFuture执行的线程中执行。例子代码如下:

3、计算结果完成时的消费(无需返回结果)

上面已经讲了结果完成时的处理和转换,他们最后的CompletableFuture都会返回对应的值,这里还会有一个只会对计算结果消费不会返回任何结果的方法。

public CompletableFuture<Void> 	thenAccept(Consumer<? super T> action)
public CompletableFuture<Void> 	thenAcceptAsync(Consumer<? super T> action)
public CompletableFuture<Void> 	thenAcceptAsync(Consumer<? super T> action, Executor executor)

T:上一个任务返回结果的类型
U:当前任务的返回值类型

当一个线程依赖另一个线程时,可以使用 thenApply 方法来把这两个线程串行化。

  1. 计算结果完成时的消费(返回结果)

这里同样也是返回CompletableFuture,但是这个结果会由我们自定义返回去转换他,同样的不以Async结尾的方法由原来的线程计算,以Async结尾的方法由默认的线程池ForkJoinPool.commonPool()或者指定的线程池executor运行。

public <U> CompletableFuture<U> thenApply(Function<? super T,? extends U> fn)
public <U> CompletableFuture<U> thenApplyAsync(Function<? super T,? extends U> fn)
public <U> CompletableFuture<U> thenApplyAsync(Function<? super T,? extends U> fn, Executor executor)
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;

public class Test1 {

    public static void main(String[] args) throws ExecutionException, InterruptedException {

        String s = "Lcuy";

        Test1 test1 = new Test1();

        CompletableFuture<String> stringCompletableFuture = CompletableFuture.supplyAsync(() -> {
            return s + " ";
        }).thenApply(name -> {
            System.out.println(name);
            return test1.hello(s);
        }).thenApply(str -> {
            System.out.println(str);
            return test1.welcome(str);
        });


        stringCompletableFuture.thenAccept(System.out::println);

        System.out.println(stringCompletableFuture.get());

        CompletableFuture.supplyAsync(() -> {
            return s + " ";
        }).thenApply(name -> {
            return test1.hello(s);
        }).thenApply(str -> {
            return test1.welcome(str);
        }).thenAccept(System.out::println);

    }

    public String hello(String name){
        return "Hello,"+name;
    }

    public String welcome(String str){
        return str + ", welcome back.";
    }
}

5、handle 方法

handle 是执行任务完成时对结果的处理。 handle 方法和 thenApply 方法处理方式基本一样。不同的是 handle 是在任务完成后再执行,还可以处理异常的任务。thenApply 只可以执行正常的任务,任务出现异常则不执行 thenApply 方法。

参考资料