Tascalate并发-填补CompletableFuture API(第1部分)的空白

Ťascalate Concurrent library provides an implementation of the CompletionStage interface and related classes these are designed to support long-running blocking tasks (typically, I/O bound). This functionality augments the sole Java 8 built-in implementation, CompletableFuture, that is primarily supports computational tasks. Also, the library helps with numerous asynchronous programing challenges like handling timeouts, retry/poll functionality, orchestrating results of multiple concurrent computations and similar.

该库以多发行版JAR的形式提供,可以与Java 8作为类路径库一起使用,也可以与Java 9+作为模块一起使用。

Why a CompletableFuture is not enough?

There are several shortcomings associated with CompletableFuture implementation that complicate its usage for real-life asynchronous programming, especially when you have to work with I/O-bound interruptible tasks:

  1. CompletableFuture.cancel() method does not interrupt underlying thread; it merely puts future to exceptionally completed state. So even if you use any blocking calls inside functions passed to thenApplyAsync / thenAcceptAsync / etc - these functions will run till the end and never will be interrupted. Please see CompletableFuture can't be interrupted by Tomasz Nurkiewicz.
  2. By default, all *Async composition methods of CompletableFutrure use ForkJoinPool.commonPool() (see here) unless explicit Executor is specified. This thread pool is shared between all CompletableFuture-s and all parallel streams across all applications deployed on the same JVM. This hard-coded, unconfigurable thread pool is completely outside of application developers' control, hard to monitor and scale. Therefore, in robust real-life applications you should always specify your own Executor. With API enhancements in Java 9+, you can fix this drawback, but it will require some custom coding.
  3. Additionally, built-in Java 8 concurrency classes provides pretty inconvenient API to combine several CompletionStage-s. CompletableFuture.allOf / CompletableFuture.anyOf methods accept only CompletableFuture as arguments; you have no mechanism to combine arbitrary CompletionStage-s without converting them to CompletableFuture first. Also, the return type of the aforementioned CompletableFuture.allOf is declared as CompletableFuture<Void> - hence you are unable to extract conveniently individual results of the each future supplied. CompletableFuture.anyOf is even worse in this regard; for more details please read on here: CompletableFuture in Action (see Shortcomings) by Tomasz Nurkiewicz.
  4. Support for timeouts/delays was introduced to CompletableFuture only in Java 9, so still widely supported applications running on Java 8 are left out without this important functionality. Plus, some design decisions like using delayed executors instead of 'delay' operator, are somewhat questionable. There are numerous free open-source libraries that address some of the aforementioned shortcomings. However, none of them provides implementation of interruptible CompletionStage and no one solves all of the issues coherently.

How to use?

要使用库,您必须添加一个Maven依赖项

<dependency>
    <groupId>net.tascalate.concurrent</groupId>
    <artifactId>net.tascalate.concurrent.lib</artifactId>
    <version>0.7.1</version>
</dependency>

What is inside?

1. Promise interface

这是Tascalate并发库的核心接口。 最好用以下公式描述:

Promise == CompletionStage + Future

I.e., it combines both blocking Future’s API, including cancel(boolean may一世nterruptIfRunning) method, AND composition capabilities of CompletionStage’s API. Importantly, all composition methods of CompletionStage API (thenAccept, thenCombine, whenComplete etc.) are re-declared to return Promise as well.

引入合并界面的决定完成阶段和未来符合设计Completable未来API。 此外,以下几种有用的方法Completable未来API也被添加:

T getNow(T valueIfAbsent) throws CancellationException, CompletionException;
T getNow(Supplier<? extends T> valueIfAbsent) throws CancellationException, CompletionException;
T join() throws CancellationException, CompletionException;

因此,使用诺言作为替代品未来发展在很多情况下。

除此之外,诺言API与超时和延迟一起使用,以覆盖默认的异步执行程序等。 所有这些都将在后面讨论。

讨论时诺言界面,必须提及附带的类诺言s提供了几种有用的方法来适应第三方完成阶段(包括标准未来发展)到诺言API。 首先,有两个单元操作可创建成功/错误的解决方案诺言-es:

static <T> Promise<T> success(T value)
static <T> Promise<T> failure(Throwable exception)

其次,有一个适配器方法从:

static <T> Promise<T> from(CompletionStage<T> stage)

它的行为如下:

  1. If the supplied stage is already a Promise then it is returned unchanged
  2. If stage is a CompletableFuture then a specially-tailored wrapper is returned.
  3. If stage additionally implements Future then specialized wrapper is returned that delegates all the blocking methods defined in Future API
  4. Otherwise generic wrapper is created with good-enough implementation of blocking Future API atop of asynchronous CompletionStage API. To summarize, the returned wrapper delegates as much as possible functionality to the supplied stage and never resorts to CompletionStage.toCompletableFuture because in Java 8 API it's an optional method. From documentation: "A CompletionStage implementation that does not choose to interoperate with others may throw UnsupportedOperationException." (this text was dropped in Java 9+). In general, Tascalate Concurrent library does not depend on this method and should be interoperable with any minimal (but valid) CompletionStage implementation.

需要强调的是,诺言-s来自诺言s.success,诺言s.failure和诺言s.from方法的取消方式与未来发展,but are not interruptible in general,while interruption depends on a concrete implementation. Next we discuss the concrete implementation of an interruptible 诺言由Tascalate并发库提供-CompletableTask类。

2. CompletableTask

This is why this project was ever started. CompletableŤask is the implementation of the Promise API for long-running blocking tasks.
Typically, to create a CompletableŤask, you should submit Supplier / Runnable to the Executor right away, in a similar way as with CompletableFuture:

Promise<SomeValue> p1 = CompletableTask.supplyAsync(() -> {
  return blockingCalculationOfSomeValue();
}, myExecutor);

Promise<Void> p2 = CompletableTask.runAsync(this::someIoBoundMethod, myExecutor);

BlockingCalculationOfSomeValue和someIoBoundMethod在上面的示例中,可以具有I / O代码,使用阻塞队列,在常规Java-s上进行阻塞获取未来-s和alike. If at later time you decide to cancel either of the returned promises then corresponding BlockingCalculationOfSomeValue和someIoBoundMethod将被中断(如果尚未完成)。

In the realm of I/O-related functionality, failures like connection time-outs, missing or locked files are pretty common, and checked exceptions mechanism is used frequently to signal failures. Therefore the library provides an entry point to the API that accepts Callable instead of Supplier:

// Notice the checked exception in the method signature
byte[] loadFile(File file) throws IOException {
    byte[] result = ... //load file content;
    return result;
}
...
ExecutorService executorService = Executors.newFixedThreadPool(6);
Promise<byte[]> contentPromise = CompletableTask.submit(
    () -> loadFile(new File("./myfile.dat")), 
    executorService
); 

此外,还有2个单元操作可以创建一个CompletableTask: 一种。CompletableTask.asyncOn(执行器执行器) 返回一个已经完成的空值诺言绑定到指定的执行者。 即 传递给的异步合成方法的任何函数诺言(喜欢thenApplyAsync/thenAcceptAsync/whenCompleteAsync etc.) will be executed using this executor unless executor is overridden via explicit composition method parameter. Moreover, any nested composition calls will use same executor, if it’s not redefined via explicit composition method parameter:

CompletableTask
  .asyncOn(myExecutor)
  .thenApplyAsync(myValueGenerator)
  .thenAcceptAsync(myConsumer)
  .thenRunAsync(myAction);

所有的myValueGenerator,myConsumer,myAction将使用执行myExecutor。 b。 CompletableTask。complete(T value,Executor executor) Same as above,but the starting point is a 诺言用指定值完成:

CompletableTask
   .complete("Hello!", myExecutor)
   .thenApplyAsync(myMapper)
   .thenApplyAsync(myTransformer)   
   .thenAcceptAsync(myConsumer)
   .thenRunAsync(myAction);

所有的myMapper,myTransformer,myConsumer,myAction将使用执行myExecutor。

最重要的是,所有组合的诺言都支持对作为参数提供的函数的真正取消(包括中断线程):

Promise<?> p1 = CompletableTask.asyncOn(myExecutor)
Promise<?> p2 = p1.thenApplyAsync(myValueGenerator)
Promise<?> p3 = p2.thenRunAsync(myAction);

...
p2.cancel(true);

In the example above myValueGenerator will be interrupted if already in progress. Both p2 and p3 will be settled with failure: p2 with a CancellationException and p3 with a CompletionException.

您可能会注意到,在术语“异步合成方法”的上方以及*异步示例中的调用(例如thenApplyAsync,thenRunAsync。 这并非偶然:非异步方法完成阶段 API are not interruptible. The grounding beneath the design decision is that invoking asynchronous methods involves inevitable overhead of putting command to the queue of the executor,starting new threads implicitly,etc. And for simple,non-blocking methods,like small calculations,trivial transformations and alike this overhead might outweigh method's execution time itself. So the guideline is: use asynchronous composition methods for heavy I/O-bound blocking tasks,and use non-asynchronous composition methods for (typically lightweight) calculations.

Worth to mention, that CompletableTask-s and Promise-s composed out of it may be ever interruptible only if the Executor used is interruptible by nature. For example, ThreadPoolExecutor supports interruptible tasks, but ForkJoinPool does not!

3. Overriding default asynchronous executor

的陷阱之一未来发展实现是如何与默认的异步执行程序一起工作的。 考虑以下示例:

CompletionStage<String> p1 = CompletableFuture.supplyAsync(this::produceValue, executorInitial);
CompletionStage<String> p2 = p1.thenApplyAsync(this::transformValueA);
CompletionStage<String> p3 = p2.thenApplyAsync(this::transformValueB, executorNext);
CompletionStage<String> p4 = p3.thenApplyAsync(this::transformValueC);

致电生产价值将在执行者初始-明确传递。 但是,transformValueS将在...执行ForkJoinPool.commonPool()! 嗯...可能这很有意义,但是默认情况下如何强制使用替代执行程序? 没门! 进行更深入的通话是否可能做到这一点? 答案再次是“否”! 调用transformValueB运行在明确提供的执行者。 但是下一个电话transformValueC将在...上执行...你猜对了...ForkJoinPool.commonPool()!

So, once you use CompletableFuture with JEE environment you must pass explicit instance of ManagedExecutor小号ervice to each and every method call. Not very convenient! To be fair, with Java 9+ API you can redefine this behavior via sub-classing CompletableFuture and overriding two methods: defaultExecutor and newIncompleteFuture. Plus, you will have to define your own "entry points" instead of the standard CompletableFuture.runAsync and CompletableFuture.supplyAsync.

用CompletableTask情况恰恰相反。 让我们重写上面的示例:

CompletionStage<String> p1 = CompletableTask.supplyAsync(this::produceValue, executorInitial);
CompletionStage<String> p2 = p1.thenApplyAsync(this::transformValueA);
CompletionStage<String> p3 = p2.thenApplyAsync(this::transformValueB, executorNext);
CompletionStage<String> p4 = p3.thenApplyAsync(this::transformValueC);

致电生产价值将在执行者初始,显然。 但是现在,transformValueS也将在执行者初始! 关于更深层次的电话呢? 调用transformValueB运行在明确提供的执行者。 接下来的电话transformValueC将执行...检查您的直觉...执行者。 其背后的逻辑如下:最新明确指定执行者没有显式使用的所有嵌套异步合成方法将使用什么执行者参数。

显然,一种尺寸适合所有尺寸的情况很少见。 因此,存在两个附加选项来指定默认的异步执行器: 一种。CompletableTask有一个重载的方法:

public static Promise<Void> asyncOn(Executor executor, boolean enforceDefaultAsync)

什么时候执行DefaultAsync是真正那么所有嵌套的异步合成方法都没有显式执行者参数将使用提供的执行程序,即使先前的编写方法使用了替代方法执行者. This是somewhat similar to 未来发展但具有最初明确设置默认异步执行程序的功能。 B.诺言界面具有以下操作:

Promise<T> defaultAsyncOn(Executor executor)

返回的装饰器将为所有嵌套的异步组合方法使用指定的执行程序,而无需显式执行者参数。 因此,您随时可以切换到所需的默认异步执行器,并继续将其用于所有嵌套的组合调用。

总而言之,使用Tascalate Concurrent,您可以使用以下选项来控制什么是默认的异步执行器:

  1. 最新显式执行者传递给*异步方法用于推导诺言-s-默认选项。单一默认执行者传递给the root CompletableTask.asyncOn(执行者 executor, true)呼叫会传播到整个链。 这是唯一受支持的变体未来发展但是在Java 9+中使用自定义编码。重新定义执行者与defaultAsyncOn(执行者 executor)对于所有派生诺言-s.Having the best of three(!) worlds, the only responsibility of the library user is to use these options consistently! The last thing that should be mentioned is a typical task when you would like to start interruptible blocking method after completion of the standard 未来发展。 以下实用程序方法在CompletableTask:
public static <T> Promise<T> waitFor(CompletionStage<T> stage, Executor executor)

大致来说,这是以下操作的快捷方式:

CompletableTask.asyncOn(executor).thenCombine(stage, (u, v) -> v);

此方法的典型用法是:

TaskExecutorService executorService = TaskExecutors.newFixedThreadPool(3);
CompletableFuture<String> replyUrlPromise = sendRequestAsync();
Promise<byte[]> dataPromise = CompletableTask.waitFor(replyUrlPromise, executorService)
    .thenApplyAsync(url -> loadDataInterruptibly(url));

的数据承诺返回的内容可能会在以后取消,并且loadDataInterruptible如果到那时还没有完成,将会被打断。

4. Timeouts

任何健壮的应用程序都必须处理出现问题的情况。 从第一天开始,库中就存在取消耗时过长的操作的功能。 但是,“太长”的定义最初留给了应用程序代码。 但是,实践表明,库中缺少经过验证的,经过全面测试的与超时相关的内容,会导致应用程序中复杂,重复且不幸的是容易出错的代码。 因此,Tascalate Concurrent已扩展为解决此遗漏。

该库提供以下操作来控制执行时间诺言(在中声明诺言接口):

<T> Promise<T> orTimeout(long timeout, TimeUnit unit[, boolean cancelOnTimeout = true])
<T> Promise<T> orTimeout(Duration duration[, boolean cancelOnTimeout = true])

These methods create a new Promise that is either settled successfully/exceptionally when original promise is completed within a timeout given; or it is settled exceptionally with a ŤimeoutException when time expired. In any case, handling code is executed on the default asynchronous Executor of the original Promise.

Executor myExecutor = ...; // Get an executor
Promise<String> callPromise = CompletableTask
    .supplyAsync( () -> someLongRunningIoBoundMehtod(), myExecutor )
    .orTimeout( Duration.ofSeconds(3) );

Promise<?> nextPromiseSync = callPromise.whenComplete((v, e) -> processResultSync(v, e));
Promise<?> nextPromiseAsync = callPromise.whenCompleteAsync((v,e) -> processResultAsync(v, e));

在上面的例子中callPromise将会在3秒内成功/异常地结算someLongRunningIoBoundMehtod执行,或者例外TimeoutException。

值得一提的是都processResultSyncandprocessRequestAsyncwillbeexecutedwithmyExecutor,iftimeoutistriggered-thisruleistrueforalltimeout-relatedmethods.

可选的cancelOnTimeout参数定义是否取消原始诺言时间到了; 省略时隐式为true。 所以在上面的例子中someLongRunningIoBoundMehtod如果需要3秒钟以上才能完成。 注意:任何诺言可以在超时时取消,即使通过诺言s.from(stage), 但只有CompletableTask可以打断!

在大多数情况下(并非总是如此),取消超时时的原始承诺是一种理想的行为。 实际上,“警告优先-取消警告-下一个”情况并不罕见,其中“警告”可能是记录日志,发送通知电子邮件,在UI上向用户显示消息等。该库提供了一个选项,用于设置多个不可取消的超时,例如 在下面的示例中:

Executor myExecutor = ...; // Get an executor
Promise<String> resultPromise = CompletableTask
    .supplyAsync( () -> someLongRunningIoBoundMehtod(), executor );

// Show UI message to user to let him/her know that everything is under control
Promise<?> t1 = resultPromise
    .orTimeout( Duration.ofSeconds(2), false )
    .exceptionally( e -> {
      if (e instanceof TimeoutException) {
        UI.showMessage("The operation takes longer than expected, please wait...");
      }
      return null;
    }, false); 

// Show UI confirmation to user to let him/her cancel operation explicitly
Promise<?> t2 = resultPromise
    .orTimeout( Duration.ofSeconds(5), false )
    .exceptionally( e -> {
      if (e instanceof TimeoutException) {
        UI.clearMessages();
        UI.showConfirmation("Service does not respond. Do you whant to cancel (Y/N)?");
      }
      return null;
    }, false); 

// Cancel in 10 seconds
resultPromise.orTimeout( Duration.ofSeconds(10), true );

请注意,超时从呼叫到或超时方法。 因此,如果您有一连串未解决的承诺,以或超时调用,则整个链应在给定的时间内完成:

Executor myExecutor = ...; // Get an executor
Promise<String> parallelPromise = CompletableTask
    .supplyAsync( () -> someLongRunningDbCall(), executor );
Promise<List<String>> resultPromise = CompletableTask
    .supplyAsync( () -> someLongRunningIoBoundMehtod(), executor )
    .thenApplyAsync( v -> converterMethod(v) )
    .thenCombineAsync(parallelPromise, (u, v) -> Arrays.asList(u, v))
    .orTimeout( Duration.ofSeconds(5) );

在最新的例子中resultPromise只要且仅当所有someLongRunningIoBoundMehtod,converterMethod乃至someLongRunningDbCall are completed within 5 seconds. If it's necessary to restrict execution time of the single step,please use standard CompletionStage.thenCompose method. Say,that in the previous example we have to restrict execution time of the converterMethod只要。 然后,修改后的链将如下所示:

Promise<List<String>> resultPromise = CompletableTask
    .supplyAsync( () -> someLongRunningIoBoundMehtod(), executor )
    // Restict only execution time of converterMethod
    // -- start of changes
    .thenCompose( v -> 
        CompletableTask.complete(v, executor)
                       .thenApplyAsync(vv -> converterMethod(vv))
                       .orTimeout( Duration.ofSeconds(5) )
    )
    // -- end of changes
    .thenCombineAsync(parallelPromise, (u, v) -> Arrays.asList(u, v))
    ;

而且,在原版的仅作为示例thenCombineAsync会在超时(链中的最后一个)时被取消,要取消整个链,必须使用依存承诺接口(将在下一篇文章中讨论)。

另一个与超时相关的有用方法声明为诺言界面有:

<T> Promise<T> onTimeout(T value, long timeout, TimeUnit unit[, boolean cancelOnTimeout = true])
<T> Promise<T> onTimeout(T value, Duration duration[, boolean cancelOnTimeout = true])
<T> Promise<T> onTimeout(Supplier<? extends T>, long timeout, TimeUnit unit[, boolean cancelOnTimeout = true])
<T> Promise<T> onTimeout(Supplier<? extends T>, Duration duration[, boolean cancelOnTimeout = true])

The onŤimeout family of methods are similar in all regards to the orŤimeout methods with the single obvious difference - instead of completing resulting Promise exceptionally with the ŤimeoutException when time is expired, they are settled successfully with the alternative value supplied (either directly or via Supplier):

Executor myExecutor = ...; // Get an executor
Promise<String> callPromise = CompletableTask
    .supplyAsync( () -> someLongRunningIoBoundMehtod(), executor )
    .onTimeout( "Timed-out!", Duration.ofSeconds(3) );

该示例表明,callPromise将会在3秒内成功/异常地结算someLongRunningIoBoundMehtod执行或具有默认值“时间到!”当时间超出时。

重要的是要提到诺言。orTimeot/onTimeout和未来发展。orTimeout/completeOnTimeout在Java9+中。在Tascalate并发中,两个操作都返回a新诺言,thatismaybecanceledindividually,withoutcancellingtheoriginal诺言。Moreover,theoriginal诺言willnotbecompletedwithTimeoutExceptionwhentimeexpiredbutratherwiththeCancellationException(inthecaseoforTimeout([duration],true)ororTimeout([持续时间]))。Thebehaviorof未来发展inJava9+isradicallydifferent:timeout-relatedoperationsarejust"side-effects",和thereturnedvalueistheoriginal未来发展itself。Sothecallto未来的。orTimeout(100,TimeUnit。MILLIS)。cancel()willcancelthe未来的itself,和thereisnowaytorevertthetimeoutonceit'sset。Correspondingly,whentimeexpiredtheoriginal未来的willbecompletedexceptionallywithTimeoutException。

最后,诺言接口提供了将延迟插入呼叫链的选项:

<T> Promise<T> delay(long timeout, TimeUnit unit[, boolean delayOnError = true])
<T> Promise<T> delay(Duration duration[, boolean delayOnError = true])

延迟仅在原始诺言成功完成或异常完成(与或超时/onTimeout立即开始超时的方法)。 造成的延迟诺言在指定的超时后解决,结果与原始结果相同诺言。 最新方法的论点-delayOnError - specifies whether or not we should delay if original 诺言 is resolved exceptionally, by default this argument is 真正。 如果假,然后延迟诺言失败的原稿后立即完成诺言。

Executor myExecutor = ...; // Get an executor
Promise<String> callPromise1 = CompletableTask
    .supplyAsync( () -> someLongRunningIoBoundMehtod(), executor )
    .delay( Duration.ofSeconds(1) ) // Give a second for CPU to calm down :)
    .thenApply(v -> convertValue(v));

Promise<String> callPromise2 = CompletableTask
    .supplyAsync( () -> aletrnativeLongRunningIoBoundMehtod(), executor )
    .delay( Duration.ofSeconds(1), false ) // Give a second for CPU to calm down ONLY on success :)
    .thenApply(v -> convertValue(v));

与其他与超时相关的方法一样,convertValue在默认的异步调用执行者原始的诺言。

您可能会注意到,延迟可能仅在链的中间引入,但是如果您想推迟整个链的执行该怎么办? 只是从一个坚定的承诺开始!

// Option 1
// Interruptible tasks chain on the executor supplied
CompletableTask.asyncOn(executor)
    .delay( Duration.ofSeconds(5) )
    .thenApplyAsync(ignore -> produceValue());

// Option2
// Computational tasks on ForkJoinPool.commonPool()
Promises.from(CompletableFuture.completedFuture(""))
    .delay( Duration.ofSeconds(5) )
    .thenApplyAsync(ignore -> produceValue());

只要退避执行不是非常罕见的情况,该库就会在CompletableTask类:

static Promise<Duration> delay(long timeout, TimeUnit unit, Executor executor);
static Promise<Duration> delay(Duration duration, Executor executor);

Notice, that in Java 9+ a different approach is chosen to implement delays - there is no corresponding operation defined for the CompletableFuture object and you should use delayed Executor. Please read documentation on the CompletableFuture.delayedExecutor method for details.

5. Combining several CompletionStage-s.

实用类承诺提供了丰富的方法来组合几种完成阶段-s,留下了有限的功能CompletableFuter.allOf / anyOf差得远:

  1. 该库可与任何完成阶段实现而无需将参数转换为未来发展首先(和完成阶段.to未来发展是可选操作,至少在Java 8中对此进行了记录。可以传递数组或清单的完成阶段-s作为参数。所结果的诺言 let access individual results的the settled 完成阶段-s通过。有一个选项可以取消未结算完成阶段-s passed once the result的the operation is known.(可选)您可以指定是否允许单个故障,只要它们不影响最终结果。一般M completed successfully out的N passed promises scenario is possible.Let us review the relevant methods, from the simplest ones to the most advance.
static <T> Promise<List<T>> all([boolean cancelRemaining=true,] 
                                 CompletionStage<? extends T>... promises)
static <T> Promise<List<T>> all([boolean cancelRemaining=true,] 
                                List<? extends CompletionStage<? extends T>> promises)

返回所有情况下正常完成的承诺完成阶段作为参数传递的-s正常完成; 如果有任何承诺异常完成,那么最终的承诺也将异常完成。

static <T> Promise<T> any([boolean cancelRemaining=true,] 
                          CompletionStage<? extends T>... promises)
static <T> Promise<T> any([boolean cancelRemaining=true,] 
                          List<? extends CompletionStage<? extends T>> promises)

返回在任何情况下正常完成的承诺完成阶段参数正常完成传递(可以进行竞赛); 如果所有的承诺都异常完成,那么最终的承诺也将异常完成。

static <T> Promise<T> anyStrict([boolean cancelRemaining=true,] CompletionStage<? extends T>... promises)
static <T> Promise<T> anyStrict([boolean cancelRemaining=true,] 
                                List<? extends CompletionStage<? extends T>> promises)

返回在任何情况下正常完成的承诺完成阶段参数正常完成传递(可以进行竞赛); 如果有任何承诺在第一个结果可用之前就异常完成,那么所产生的承诺也会在异常情况下完成(与非严格变体不同,如果有任何结果可用,则忽略异常)。

static <T> Promise<List<T>> atLeast(int minResultsCount, [boolean cancelRemaining=true,] 
                                    CompletionStage<? extends T>... promises)
static <T> Promise<List<T>> atLeast(int minResultsCount, [boolean cancelRemaining=true,] 
                                    List<? extends CompletionStage<? extends T>> promises)

泛化任何方法。 返回至少在以下情况下正常完成的承诺minResultCount 的完成阶段作为参数传递的-s正常完成(可以进行竞赛); 如果少于minResultCount的诺言正常完成,然后产生的诺言异常完成。

static <T> Promise<List<T>> atLeastStrict(int minResultsCount, [boolean cancelRemaining=true,] 
                                          CompletionStage<? extends T>... promises)
static <T> Promise<List<T>> atLeastStrict(int minResultsCount, [boolean cancelRemaining=true,] 
                                          List<? extends CompletionStage<? extends T>> promises)

泛化任何严格方法。 返回至少在以下情况下正常完成的承诺minResultCount的完成阶段作为参数传递的-s正常完成(可以进行竞赛); 如果有任何约定在之前完成minResultCount的results are available, then resulting promise is completed exceptionally as well (unlike non-Strict variant, where exceptions are ignored if minResultsCount的successful results are available).

以上所有方法都有一个可选参数cancel剩余。 如果省略,则意味着隐式cancel剩余 = true。 的cancel剩余参数定义是否急于取消剩余诺言一旦知道运算结果,即足够诺言通过,结算成功要么一些完成阶段严格版本中例外完成。

Each operation to combine CompletionStage-s has overloaded versions that accept either a List of CompletionStage-s or varagr array of CompletionStage-s.

除了任何/任何Strict返回单值promise的方法,所有其他组合方法将在相同的索引位置为每个成功完成的promise返回值列表。 如果给定位置的承诺根本没有兑现或失败(在非严格版本中),则结果列表中的对应项为空值。 如有必要,请致电或诺言 was not completed successfully, or 任何 one completed exceptionally in strict version, then resulting 诺言因类型错误而解决MultitargetException。 应用程序开发人员可以检查多targetException.get Exceptions()检查每种混凝土的确切破坏是什么完成阶段通过了。 的诺言返回具有以下特征:

  1. 取消结果诺言将取消所有完成阶段作为参数传递。结果的默认异步执行器诺言是未定义的,即可能是ForkJoin.commonPool管他呢执行者由任何完成阶段作为参数传递。 确保必要的默认值执行者用于后续异步操作,请申请defaultAsyncOn(my执行者)结果。

The list of features provided by the Tascalate Concurrent library doesn't stop here. There is more interesting stuff like Retry / Poll functionality, controlling cancellation of the chain of Promises, extensions to ExecutorService etc. But this post is already getting too long, so the reamaing is left for the next time. In the meantime, you can check the home page of the Ťascalate Concurrent library for the most up-to-date documentation.

github-logo-6a5bca60a4ebf959a6df7f08217acd07ac2bc285164fae041eacb8a148b1bab9.svgvsilaev / tascalate-concurrent

Implementation of blocking (IO-Bound) cancellable java.util.concurrent.CompletionStage and related extensions to java.util.concurrent.ExecutorService-s

Maven Central GitHub release license

tascalate-concurrent

The library provides an implementation of the CompletionStage interface and related classes these are designed to support long-running blocking tasks (typically, I/O bound). This functionality augments the sole Java 8 built-in implementation, CompletableFuture, that is primarily supports computational tasks. Also, the library helps with numerous asynchronous programing challenges like handling timeouts, retry/poll functionality, orchestrating results of multiple concurrent computations and similar.

Since the version 0.7.0 the library is shipped as a multi-release JAR and may be used both with Java 8 as a classpath library or with Java 9+ as a module.

Why a CompletableFuture is not enough?

There are several shortcomings associated with CompletableFuture implementation that complicate its usage for real-life asynchronous programming, especially when you have to work with I/O-bound interruptible tasks:

  1. CompletableFuture.cancel() method does not interrupt underlying thread; it merely puts future to exceptionally completed state. So even if you use any blocking calls inside…

Acknowledgements

Internal implementation details of the CompletableTask class hierarchy are greatly inspired by the work done by Lukáš Křečan. A description of his library is available as a two-part article on DZone: Part 1 and Part 一世I. It's a worth reading for those, who'd like to have better understanding of the CompletableTask internals.

from: https://dev.to//vsilaev/tascalate-concurrent---filling-the-gaps-in-completablefuture-api-part-1-7lm

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值