CompletableFuture实现异步任务

本文参考:https://blog.csdn.net/arjun_yu/article/details/112993354

CompletableFutureFuture API的扩展。

Future 被用于作为一个异步计算结果的引用。提供一个 isDone() 方法来检查计算任务是否完成。当任务完成时,get() 方法用来接收计算任务的结果。

项目需求:

项目中需要优化一个接口,这个接口需要拉取2,3个第三方接口,需求延迟时间小于200ms;

技术选型:

在Java中CompletableFuture用于异步编程,异步编程是编写非阻塞的代码,运行的任务在一个单独的线程,与主线程隔离,并且会通知主线程它的进度,成功或者失败。

在这种方式中,主线程不会被阻塞,不需要一直等到子线程完成。主线程可以并行的执行其他任务。使用这种并行方式,可以极大的提高程序的性能。

CompletableFutureJDK8提出的一个支持非阻塞的多功能的Future,同样也是实现了Future接口,FutureJava 5添加的类,用来描述一个异步计算的结果。java8对future进一步完善,扩展了诸多功能形成了CompletableFuture,它拥有Future所有的功能,包括获取异步执行结果,取消正在执行的任务等。

1、CompletableFuture功能介绍

CompletableFuture还是一个CompletionStage

我们看下CompletableFuture的定义:

public class CompletableFuture<T> implements Future<T>, CompletionStage<T>

什么是CompletionStage呢?

在异步程序中,如果将每次的异步执行都看成是一个stage的话,我们通常很难控制异步程序的执行顺序,在javascript中,我们需要在回调中执行回调。这就会形成传说中的回调地狱。

好在在ES6中引入了promise的概念,可以将回调中的回调转写为链式调用,从而大大的提升了程序的可读性和可写性。

同样的在java中,我们使用CompletionStage来实现异步调用的链式操作。CompletionStage定义了一系列的then*** 操作来实现这一功能。

详见:https://segmentfault.com/a/1190000022197398

2、使用CompletableFuture作为Future实现

使用无构参构造函数创建此类的实例

CompletableFuture<String> completableFuture = new CompletableFuture<String>();

这是一个最简单的 CompletableFuture,想获取CompletableFuture 的结果可以使用 CompletableFuture.get() 方法:

String result = completableFuture.get()

get() 方法会一直阻塞直到 Future 完成。因此,以上的调用将被永远阻塞,因为该Future一直不会完成。

另请注意,get方法抛出一些已检查的异常,即ExecutionException(封装计算期间发生的异常)和InterruptedException(表示执行方法的线程被中断的异常)

你可以使用 CompletableFuture.complete() 手工的完成一个 Future:

completableFuture.complete("Future's Result")

所有等待这个 Future 的客户端都将得到一个指定的结果,并且 completableFuture.complete() 之后的调用将被忽略。

public Future<String> calculateAsync() {

    CompletableFuture<String> completableFuture = new CompletableFuture<>();

    Executors.newCachedThreadPool().submit(() -> {
        Thread.sleep(500);
        completableFuture.complete("Hello");
        return null;
    });

    return completableFuture;
}

这种创建和完成CompletableFuture的方法可以与任何并发包(包括原始线程)一起使用。

如果你知道执行的结果,那么可以使用CompletableFuturecompletedFuture方法来直接返回一个Future。

public Future<String> useCompletableFuture(){
    Future<String> completableFuture =
            CompletableFuture.completedFuture("Hello");
    return completableFuture;
}

假设我们没有找到结果并决定完全取消异步执行任务。CompletableFuture还提供了一个cancel方法来立马取消任务的执行。

public Future<String> calculateAsyncWithCancellation() {
    
    CompletableFuture<String> completableFuture = new CompletableFuture<>();

    Executors.newCachedThreadPool().submit(() -> {
        Thread.sleep(500);
        completableFuture.cancel(false);
        return null;
    });
    
    return completableFuture;
}

当我们使用Future.get()方法阻塞结果时,cancel()表示取消执行,它将抛出CancellationException异常。java.util.concurrent.CancellationException

3、异步执行

上面的代码很简单,下面介绍几个 static 方法,它们使用任务来实例化一个 CompletableFuture 实例。

CompletableFuture提供了runAsyncsupplyAsync的方法,可以以异步的方式执行代码。

CompletableFuture.runAsync(Runnable runnable);
CompletableFuture.runAsync(Runnable runnable, Executor executor);

CompletableFuture.supplyAsync(Supplier<U> supplier);
CompletableFuture.supplyAsync(Supplier<U> supplier, Executor executor)

这两个方法是executor 的升级,表示让任务在指定的线程池中执行,不指定的话,通常任务是在 ForkJoinPool.commonPool() 线程池中执行的

3.1、runAsync()

方法接收的是 Runnable 的实例,但是它没有返回值

public void runAsync() {
    CompletableFuture.runAsync(() -> {
        LOGGER.info("初始化CompletableFuture子任务! runAsync");
    }, Executors.newFixedThreadPool(3));
}

3.2、supplyAsync()

方法是JDK8函数式接口,无参数,会返回一个结果

public void supplyAsync() throws ExecutionException, InterruptedException {

    CompletableFuture<String> future = CompletableFuture.supplyAsync(new Supplier<String>() {
        @Override
        public String get() {
            LOGGER.info("初始化CompletableFuture子任务! supplyAsync");
            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                throw new IllegalStateException(e);
            }
            return "Result of the asynchronous computation";
        }
    });

    String result = future.get();
    LOGGER.info(result);
}

使用lambda表达式使得上面的示例更加简明:

CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
    LOGGER.info("初始化CompletableFuture子任务! supplyAsync");
    try {
        TimeUnit.SECONDS.sleep(1);
    } catch (InterruptedException e) {
        throw new IllegalStateException(e);
    }
    return "Result of the asynchronous computation";
});

4、转换和运行

对于构建异步系统,我们应该附上一个回调给CompletableFuture,当Future完成的时候,自动的获取结果。如果我们不想等待结果返回,我们可以把需要等待Future完成执行的逻辑写入到回调函数中。可以使用thenApplyAsync(), thenAccept()thenRun()方法附上一个回调给CompletableFuture

为了控制执行回调任务的线程,你可以使用异步回调。将从ForkJoinPool.commonPool()获取不同的线程执行。此外,如果你传入一个ExecutorthenApplyAsync()回调中,,任务将从Executor线程池获取一个线程执行。

4.1、 thenApplyAsync()

在两个任务任务A,任务B中,任务B想要任务A计算的结果,可以用thenApplyAsync方法来接受一个函数实例,用它来处理结果,并返回一个Future函数的返回值:

模板

CompletableFuture.runAsync(() -> {}).thenApply(resultA -> "resultB");
CompletableFuture.supplyAsync(() -> "resultA").thenApply(resultA -> resultA + " resultB");

任务 A 执行完执行 B,B 需要 A 的结果,同时任务 B 有返回值。

多个任务的情况下,如果任务 B 后面还有任务 C,往下继续调用.thenApplyAsync()即可。

实战

public void supplyAsync() throws ExecutionException, InterruptedException {

    CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
        LOGGER.info("初始化CompletableFuture子任务! supplyAsync");
        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            throw new IllegalStateException(e);
        }
        return "Result of the asynchronous computation";
    });
    
    CompletableFuture<String> completableFuture = future.thenApplyAsync(resultA -> {
        LOGGER.info(resultA);
        return "Hello " + resultA;
    }).thenApplyAsync(resultB -> {
        LOGGER.info(resultB);
        return resultB + ", Welcome to the arjun Blog";
    });

    System.out.println(completableFuture.get());
    // Prints - Hello Result of the asynchronous computation, Welcome to the arjun Blog
}

4.2、thenAcceptAsync()

在两个任务任务A,任务B中,如果你不需要在Future中有返回值,则可以用 thenAcceptAsync方法接收将计算结果传递给它。最后的future.get()调用返回Void类型的实例。CompletableFuture.thenAcceptAsync()持有一个Consumer<T>,返回一个CompletableFuture<Void>。它可以访问CompletableFuture的结果:

模板

CompletableFuture.runAsync(() -> {}).thenAccept(resultA -> {}); 

CompletableFuture.supplyAsync(() -> "resultA").thenAccept(resultA -> {});
  • runAsync不会有返回值,方法thenAcceptAsync,接收到的resultA值为null,同时任务B也不会有返回结果

  • supplyAsync有返回值,同时任务B不会有返回结果。

实战

public void supplyAsync() throws ExecutionException, InterruptedException {

    CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
        LOGGER.info("初始化CompletableFuture子任务! supplyAsync");
        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            throw new IllegalStateException(e);
        }
        return "Result of the asynchronous computation";
    });
    
    CompletableFuture<Void> completableFuture = future.thenAcceptAsync(resultA -> {
        LOGGER.info("Computation returned: {}", resultA);
    });

    System.out.println(completableFuture.get());
    // Prints - null
}

4.3、thenRunAsync()

如果你不想从你的回调函数中返回任何东西,仅仅想在Future完成后运行一些代码片段,你可以使用thenAcceptAsync()thenRunAsync()方法,这些方法经常在调用链的最末端的最后一个回调函数中使用。thenRun()不能访Future的结果,它持有一个Runnable返回CompletableFuture<Void>

模板

CompletableFuture.runAsync(() -> {}).thenRun(() -> {}); 
CompletableFuture.supplyAsync(() -> "resultA").thenRun(() -> {});
  • runAsync不会有返回值,方法thenRunAsync(Runnable runnable),任务 A 执行完执行 B,并且 B 不需要 A 的结果。

  • supplyAsync有返回值,方法thenRunAsync(Runnable runnable),任务 A 执行完执行 B,会返回resultA,但是 B 不需要 A 的结果。

实战

public void supplyAsync() throws ExecutionException, InterruptedException {

    CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
        LOGGER.info("初始化CompletableFuture子任务! supplyAsync");
        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            throw new IllegalStateException(e);
        }
        return "Result of the asynchronous computation";
    });
    
    CompletableFuture<Void> completableFuture = future.thenRunAsync(() -> System.out.println("Computation finished."));
    // Prints - Computation finished.
    System.out.println(completableFuture.get());
    // Prints - null
}

5、组合Futures

上面讲到CompletableFuture的一个重大作用就是将回调改为链式调用,从而将Futures组合起来。

5.1. 使用 thenCompose()组合两个独立的future

thenCompose将前一个Future的返回结果作为后一个操作的输入。

模板

CompletableFuture<String> completableFuture = CompletableFuture.supplyAsync(() -> "Hello")
        .thenCompose(s -> CompletableFuture.supplyAsync(() -> s + " World"));

实战

假设你想从一个远程API中获取一个用户的详细信息,一旦用户信息可用,你想从另外一个服务中获取他的贷方。

考虑下以下两个方法getUserDetail()getCreditRating()的实现:

CompletableFuture<User> getUsersDetail(String userId) {
    return CompletableFuture.supplyAsync(() -> {
        UserService.getUserDetails(userId);
    });    
}

CompletableFuture<Double> getCreditRating(User user) {
    return CompletableFuture.supplyAsync(() -> {
        CreditRatingService.getCreditRating(user);
    });
}

现在让我们弄明白当使用了thenApply()后是否会达到我们期望的结果?

 CompletableFuture<CompletableFuture<Double>> result = getUsersDetail(userId)
         .thenApply(user -> getCreditRating(user));

在以上thenApply的示例中,Supplier函数传入thenApply将返回一个简单的值,但是在本例中,将返回一个CompletableFuture。以上示例的最终结果是一个嵌套的CompletableFuture
如果你想获取最终的结果给最顶层future,使用 thenCompose()方法代替

CompletableFuture<Double> result = getUsersDetail(userId)
        .thenCompose(user -> getCreditRating(user));

因此,规则就是-如果你的回调函数返回一个CompletableFuture,但是你想从CompletableFuture链中获取一个直接合并后的结果,这时候你可以使用thenCompose()。因此,如果想要继续嵌套链接CompletableFuture 方法,那么最好使用thenCompose()

thenApply()thenCompose()之间的区别

thenCompose()方法类似于thenApply()在都返回一个新的计算结果。但是,thenCompose()使用前一个Future作为参数。它会直接使结果变新的Future,而不是我们在thenApply()中到的嵌套Future,而是用来连接两个CompletableFuture,是生成一个新的CompletableFuture

5.2、使用thenCombine()组合两个独立的 future

如果要执行两个独立的任务,并对其结果执行某些操作,可以用Future的thenCombine方法。被用来当两个独立的Future都完成的时候,用来做一些事情。

模板

CompletableFuture<String> cfA = CompletableFuture.supplyAsync(() -> "resultA");
CompletableFuture<String> cfB = CompletableFuture.supplyAsync(() -> "resultB");

cfA.thenAcceptBoth(cfB, (resultA, resultB) -> {});

cfA.thenCombine(cfB, (resultA, resultB) -> "result A + B");

实战

System.out.println("Retrieving weight.");
CompletableFuture<Double> weightInKgFuture = CompletableFuture.supplyAsync(() -> {
    try {
        TimeUnit.SECONDS.sleep(1);
    } catch (InterruptedException e) {
       throw new IllegalStateException(e);
    }
    return 65.0;
});

System.out.println("Retrieving height.");
CompletableFuture<Double> heightInCmFuture = CompletableFuture.supplyAsync(() -> {
    try {
        TimeUnit.SECONDS.sleep(1);
    } catch (InterruptedException e) {
       throw new IllegalStateException(e);
    }
    return 177.8;
});

System.out.println("Calculating BMI.");
CompletableFuture<Double> combinedFuture = weightInKgFuture
        .thenCombine(heightInCmFuture, (weightInKg, heightInCm) -> {
    Double heightInMeter = heightInCm/100;
    return weightInKg/(heightInMeter*heightInMeter);
});

System.out.println("Your BMI is - " + combinedFuture.get());

当两个Future都完成的时候,传给thenCombine()的回调函数将被调用。

5.3、使用thenAcceptBoth()组合两个独立的 future

更简单的情况是,当你想要使用两个Future结果时,但不需要将任何结果值进行返回时,可以用thenAcceptBoth,它表示后续的处理不需要返回值,而 thenCombine 表示需要返回值:

如果你不想返回结果,则可以使用thenAcceptBoth

CompletableFuture<Void> completableFuture = CompletableFuture.supplyAsync(() -> "Hello")
        .thenAcceptBoth(CompletableFuture.supplyAsync(() -> " World"), (s1, s2) -> System.out.println(s1 + s2));

6、并行运行多个任务

我们使用thenCompose()thenCombine()把两个CompletableFuture组合在一起。当我们需要并行执行多个任务时,我们通常希望等待所有它们执行,然后处理它们的组合结果。现在如果你想组合任意数量的CompletableFuture,应该怎么做?

我们可以使用以下两个方法组合任意数量的CompletableFuture

API

public static CompletableFuture<Void> allOf(CompletableFuture<?>... cfs){...}
public static CompletableFuture<Object> anyOf(CompletableFuture<?>... cfs){...}

6.1、CompletableFuture.allOf()

CompletableFuture.allOf静态方法允许等待所有的完成任务:

CompletableFuture.allOf的使用场景是当你一个列表的独立future,并且你想在它们都完成后并行的做一些事情。

实战场景

假设你想下载一个网站的100个不同的页面。你可以串行的做这个操作,但是这非常消耗时间。因此你想写一个函数,传入一个页面链接,返回一个CompletableFuture,异步的下载页面内容。

CompletableFuture<String> downloadWebPage(String pageLink) {
    return CompletableFuture.supplyAsync(() -> {
        // TODO Code to download and return the web page's content
    });
} 

现在,当所有的页面已经下载完毕,你想计算包含关键字CompletableFuture页面的数量。可以使用CompletableFuture.allOf()达成目的。

List<String> webPageLinks = Arrays.asList(...)    // A list of 100 web page links

// Download contents of all the web pages asynchronously
List<CompletableFuture<String>> pageContentFutures = webPageLinks.stream()
        .map(webPageLink -> downloadWebPage(webPageLink))
        .collect(Collectors.toList());

// Create a combined Future using allOf()
CompletableFuture<Void> allFutures = CompletableFuture.allOf(
        pageContentFutures.toArray(new CompletableFuture[pageContentFutures.size()])
);

使用CompletableFuture.allOf()的问题是它返回CompletableFuture<Void>。这种方法的局限性在于它不会返回所有任务的综合结果。相反,你必须手动从Futures获取结果。幸运的是,CompletableFuture.join()方法和Java 8 Streams API可以解决:

// When all the Futures are completed, call `future.join()` to get their results and collect the results in a list -
CompletableFuture<List<String>> allPageContentsFuture = allFutures.thenApply(v -> {
   return pageContentFutures.stream()
           //.map(pageContentFuture -> pageContentFuture.join())
       	   .map(CompletableFuture::join)
           .collect(Collectors.toList());
});

CompletableFuture 提供了 join() 方法,它的功能和 get() 方法是一样的,都是阻塞获取值,它们的区别在于 join() 抛出的是 unchecked Exception。这使得它可以在Stream.map()方法中用作方法引用。

现在让我们计算包含关键字页面的数量。

 // Count the number of web pages having the "CompletableFuture" keyword.
 CompletableFuture<Long> countFuture = allPageContentsFuture.thenApply(pageContents -> {
     return pageContents.stream()
             .filter(pageContent -> pageContent.contains("CompletableFuture"))
             .count();
 });

 System.out.println("Number of Web Pages having CompletableFuture keyword - " + countFuture.get());

6.2、CompletableFuture.anyOf()

CompletableFuture.anyOf()和其名字介绍的一样,当任何一个CompletableFuture完成的时候【相同的结果类型】,返回一个新的CompletableFuture

CompletableFuture<String> future1 = CompletableFuture.supplyAsync(() -> {
    try {
        TimeUnit.SECONDS.sleep(2);
    } catch (InterruptedException e) {
       throw new IllegalStateException(e);
    }
    return "Result of Future 1";
});

CompletableFuture<String> future2 = CompletableFuture.supplyAsync(() -> {
    try {
        TimeUnit.SECONDS.sleep(1);
    } catch (InterruptedException e) {
       throw new IllegalStateException(e);
    }
    return "Result of Future 2";
});

CompletableFuture<String> future3 = CompletableFuture.supplyAsync(() -> {
    try {
        TimeUnit.SECONDS.sleep(3);
    } catch (InterruptedException e) {
       throw new IllegalStateException(e);
    }
    return "Result of Future 3";
});

CompletableFuture<Object> anyOfFuture = CompletableFuture.anyOf(future1, future2, future3);

System.out.println(anyOfFuture.get()); 
// Prints - Result of Future 2

在以上示例中,当三个中的任何一个CompletableFuture完成, anyOfFuture就会完成。因为future2的休眠时间最少,因此它最先完成,最终的结果将是future2的结果。

CompletableFuture.anyOf()传入一个Future可变参数,返回CompletableFuture<Object>CompletableFuture.anyOf()的问题是如果你的CompletableFuture返回的结果是不同类型的,这时候你讲会不知道你最终CompletableFuture是什么类型。

7、异常处理

我们探寻了怎样创建CompletableFuture,转换它们,并组合多个CompletableFuture。现在让我们弄明白当发生错误的时候我们应该怎么做。

首先让我们明白在一个回调链中错误是怎么传递的。思考下以下回调链:

CompletableFuture.supplyAsync(() -> {
    // Code which might throw an exception
    return "Some result";
}).thenApply(result -> {
    return "processed result";
}).thenApply(result -> {
    return "result after further processing";
}).thenAccept(result -> {
    // do something with the final result
});

如果在原始的supplyAsync()任务中发生一个错误,这时候没有任何thenApply会被调用并且future将以一个异常结束。如果在第一个thenApply发生错误,这时候第二个和第三个将不会被调用,同样的,future将以异常结束。

7.1、使用 exceptionally() 回调处理异常

exceptionally()回调给你一个从原始Future中生成的错误恢复的机会。你可以在这里记录这个异常并返回一个默认值。

API

public CompletableFuture<T> exceptionally(Function<Throwable, ? extends T> fn);

看下代码

CompletableFuture.supplyAsync(() -> "resultA")
    .thenApply(resultA -> resultA + " resultB")
    .thenApply(resultB -> resultB + " resultC")
    .thenApply(resultC -> resultC + " resultD");

上面的代码中,任务 A、B、C、D 依次执行,如果任务 A 抛出异常(当然上面的代码不会抛出异常),那么后面的任务都得不到执行。如果任务 C 抛出异常,那么任务 D 得不到执行。

那么我们怎么处理异常呢?看下面的代码,我们在任务 A 中抛出异常,并对其进行处理:

CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
    throw new RuntimeException();
})
        .exceptionally(ex -> "ERROR - ResultA")
        .thenApply(resultA -> resultA + ", resultB")
        .thenApply(resultB -> resultB + ", resultC")
        .thenApply(resultC -> resultC + ", resultD");
System.out.println(future.join());
// Prints - ERROR - ResultA, resultB, resultC, resultD

上面的代码中,任务 A 抛出异常,然后通过.exceptionally() 方法处理了异常,并返回新的结果,这个新的结果将传递给任务 B。

实战情景

Integer age = -1;

CompletableFuture<String> maturityFuture = CompletableFuture.supplyAsync(() -> {
    if(age < 0) {
        throw new IllegalArgumentException("Age can not be negative");
    }
    if(age > 18) {
        return "Adult";
    } else {
        return "Child";
    }
}).exceptionally(ex -> {
    LOGGER.error("Oops! We have an exception - {}", ex.getMessage());
    return "Unknown!";
});

System.out.println("Maturity : " + maturityFuture.get()); 
// Prints - Maturity : Unknown!

7.2、使用 handle() 方法处理异常

API提供了一个更通用的方法 - handle()从异常恢复,无论一个异常是否发生它都会被调用。

API

public <U> CompletionStage<U> handle(BiFunction<? super T, Throwable, ? extends U> fn);

如果在链式调用的时候抛出异常,则可以在最后使用handle来接收。

public void handleError() throws ExecutionException, InterruptedException {
    String name = null;
    
    CompletableFuture<String> completableFuture
            =  CompletableFuture.supplyAsync(() -> {
        if (name == null) {
            throw new RuntimeException("Computation error!");
        }
        return "Hello, " + name;
    }).handle((res, ex) -> res != null ? res : "Hello, Stranger!");

    System.out.println(completableFuture.get());
    // Prints - Hello, Stranger!
}

实战情景

Integer age = -1;

CompletableFuture<String> maturityFuture = CompletableFuture.supplyAsync(() -> {
    if(age < 0) {
        throw new IllegalArgumentException("Age can not be negative");
    }
    if(age > 18) {
        return "Adult";
    } else {
        return "Child";
    }
}).handle((res, ex) -> {
    if(ex != null) {
        LOGGER.error("Oops! We have an exception - {}", ex.getMessage());
        return "Unknown!";
    }
    return res;
});

System.out.println("Maturity : " + maturityFuture.get());
// Prints - Maturity : Unknown!

如果异常发生,res参数将是 null,否则,ex将是 null。

7.3、使用whenComplete()方法处理异常

API

public CompletableFuture<T> whenComplete(BiConsumer<? super T, ? super Throwable> action);

返回传进去的值

CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
    // long running task
    throw new RuntimeException("error!");
});

future.whenComplete((result, exception) -> {
    if (null == exception) {
        System.out.println("result from previous task: " + result);
    } else {
        System.err.println("Exception thrown from previous task: " + exception.getMessage());
    }
});

exceptionally()的使用非常类似于try{}catch{}中的catch{},但是由于支持链式编程方式,所以相对更简单。

whenComplete()handle()系列方法就类似于 try{}finally{}中的finally{},无论是否发生异常都会执行 whenComplete()中的回调函数 BiConsumerhandle()中的回调函数 BiFunction。顾名思义,BiConsumer是直接消费的,而BiFunction是有返回值的,

whenComplete()handle() 的区别在于whenComplete()不支持返回结果,而handle()是支持返回结果的。

8、Async后缀方法

CompletableFuture类中的API的大多数方法都有两个带有Async后缀的附加修饰。这些方法表示用于异步线程。

没有Async后缀的方法使用调用线程运行下一个执行线程阶段。不带Async方法使用ForkJoinPool.commonPool()线程池的fork / join实现运算任务。带有Async方法使用传递式的Executor任务去运行。

9、JDK 9 CompletableFuture API

Java 9中, CompletableFuture API通过以下更改得到了进一步增强:

  • 新工厂方法增加了
  • 支持延迟和超时
  • 改进了对子类化的支持。

引入了新的实例API

  • Executor defaultExecutor()
  • CompletableFuture<U> newIncompleteFuture()
  • CompletableFuture<T> copy()
  • CompletionStage<T> minimalCompletionStage()
  • CompletableFuture<T> completeAsync(Supplier<? extends T> supplier, Executor executor)
  • CompletableFuture<T> completeAsync(Supplier<? extends T> supplier)
  • CompletableFuture<T> orTimeout(long timeout, TimeUnit unit)
  • CompletableFuture<T> completeOnTimeout(T value, long timeout, TimeUnit unit)

还有一些静态实用方法:

  • Executor delayedExecutor(long delay, TimeUnit unit, Executor executor)
  • Executor delayedExecutor(long delay, TimeUnit unit)
  • <U> CompletionStage<U> completedStage(U value)
  • <U> CompletionStage<U> failedStage(Throwable ex)
  • <U> CompletableFuture<U> failedFuture(Throwable ex)

最后,为了解决超时问题,Java 9又引入了两个新功能:

  • orTimeout()
  • completeOnTimeout()
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值