Skip to content

Commit

Permalink
docs: add docs in README and javadoc 📚
Browse files Browse the repository at this point in the history
- `mostOf*` method
- `default executor`
  • Loading branch information
oldratlee committed Jun 10, 2024
1 parent 02e095a commit 8eb1040
Show file tree
Hide file tree
Showing 3 changed files with 112 additions and 60 deletions.
24 changes: 16 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -69,8 +69,9 @@
- 更高效灵活的并发执行策略,如
- `allOfFastFail`方法:有`CF`失败时快速返回,而不再等待所有`CF`运行完成(`allOf`
- `anyOfSuccess`方法:返回首个成功的`CF`结果,而不是首个完成(但可能失败)的`CF``anyOf`
- `mostResultsOfSuccess`方法:返回指定时间内成功`CF`的结果,忽略失败或还没有运行完成的`CF`(使用缺省值)
- 更安全的使用方式,如
- 支持设置缺省的业务线程池`CffuFactory#builder(executor)`方法
- 支持设置缺省的业务线程池并封装可携带`CffuFactory#builder(executor)`方法
- 支持超时的`join`的方法,`join(timeout, unit)`方法
- 支持禁止强制篡改,`CffuFactoryBuilder#forbidObtrudeMethods`方法
- 在类方法附加完善的代码质量注解(如`@NonNull``@Nullable``@CheckReturnValue``@Contract`等),在编码时`IDE`能尽早提示出问题
Expand All @@ -97,8 +98,8 @@
- 无需额外依赖,几乎总是可用
- 相信有极高的实现质量
- **广为人知广泛使用,有一流的群众基础**
- `CompletableFuture`在2014年发布的`Java 8`提供,有~10年了
- `CompletableFuture`的父接口[`Future`](https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/util/concurrent/Future.html)早在2004年发布的`Java 5`中提供,有~20年了
- `CompletableFuture`在2014年发布的`Java 8`提供,有10年了
- `CompletableFuture`的父接口[`Future`](https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/util/concurrent/Future.html)早在2004年发布的`Java 5`中提供,有20年了
- 虽然`Future`接口不支持 执行结果的异步获取与并发执行逻辑的编排,但也让广大`Java`开发者熟悉了`Future`这个典型的概念与工具
- **功能强大、但不会非常庞大复杂**
- 足以应对日常的业务需求开发
Expand Down Expand Up @@ -132,7 +133,7 @@
- 🛠️️ 2) **使用`CompletableFutureUtils`工具类**
- 如果你不想在项目中引入新类(`Cffu`类)、觉得这样增加了复杂性的话,
- 完全可以把`cffu`库作为一个工具类来用
- 优化`CompletableFuture`使用的工具方法在业务项目中很常见,`CompletableFutureUtils`提供了一系列实用可靠的工具方法
- 优化`CompletableFuture`使用的工具方法在业务项目中很常见,`CompletableFutureUtils`提供了一系列实用可靠高效安全的工具方法
- 这种使用方式有些`cffu`功能没有提供(也没有想到实现方案) 😔
如支持设置缺省的业务线程池、禁止强制篡改
- 依赖`io.foldright:cffu`
Expand Down Expand Up @@ -273,7 +274,7 @@ fun main() {
### 2.1 返回多个运行`CF`的结果

`CompletableFuture``allOf`方法没有返回结果,只是返回`Void`,不方便获得所运行的多个`CF`结果。
\# 要再通过入参`CF``get`方法来获取结果
\# 需要在`allOf`方法之后再通过入参`CF`的读方法(如`join`/`get`来获取结果

`cffu``allResultsOf`方法提供了返回多个`CF`结果的功能。

Expand Down Expand Up @@ -350,13 +351,17 @@ public class AllTupleOfDemo {

> \# 完整可运行的Demo代码参见[`AllTupleOfDemo.java`](cffu-core/src/test/java/io/foldright/demo/AllTupleOfDemo.java)
### 2.2 支持设置缺省的业务线程池
### 2.2 支持设置缺省的业务线程池并封装可携带

- `CompletableFuture`执行执行(即`CompletableFuture``*Async`方法),使用的缺省线程池是`ForkJoinPool.commonPool()`
- 这个线程池差不多是`CPU`个线程,合适执行`CPU`密集的任务;对于业务逻辑,往往有很多等待操作(如网络`IO`、阻塞等待),并不是`CPU`密集的。
- 业务使用这个缺省线程池`ForkJoinPool.commonPool()`是很危险的❗

结果就是,业务调用`CompletableFuture``*Async`方法时,几乎每次都要反复传入业务线程池;这让`CompletableFuture`的使用很繁琐易错 🤯
结果就是,

- 在业务逻辑中,调用`CompletableFuture``*Async`方法时,几乎每次都要反复传入指定的业务线程池;这让`CompletableFuture`的使用很繁琐易错 🤯
- 在底层逻辑中,当底层操作回调业务时(如`RPC`回调),不合适或方便为业务提供线程池;这时使用`Cffu`封装携带的线程池既方便又合理安全
这个使用场景更多可以看看[CompletableFuture原理与实践 - 4.2.3 异步RPC调用注意不要阻塞IO线程池](https://juejin.cn/post/7098727514725416967#heading-25)

示例代码如下:

Expand Down Expand Up @@ -409,7 +414,7 @@ public class DefaultExecutorSettingForCffu {

> \# 完整可运行的Demo代码参见[`DefaultExecutorSettingForCffu.java`](cffu-core/src/test/java/io/foldright/demo/DefaultExecutorSettingForCffu.java)
### 2.3 高效灵活的并发执行策略(`allOfFastFail`/`anyOfSuccess`
### 2.3 高效灵活的并发执行策略(`allOfFastFail`/`anyOfSuccess`/`mostResultsOfSuccess`

- `CompletableFuture``allOf`方法会等待所有输入`CF`运行完成;即使有`CF`失败了也要等待后续`CF`运行完成,再返回一个失败的`CF`
- 对于业务逻辑来说,这样失败且继续等待策略,减慢了业务响应性;会希望如果有输入`CF`失败了,则快速失败不再做于事无补的等待
Expand All @@ -419,6 +424,9 @@ public class DefaultExecutorSettingForCffu {
- 对于业务逻辑来说,会希望赛马模式返回首个成功的`CF`结果,而不是首个完成但失败的`CF`
- `cffu`提供了相应的`anyOfSuccess`方法
- `anyOfSuccess`只有当所有的输入`CF`都失败时,才返回失败结果
- 返回指定时间内成功`CF`的结果,忽略失败或还没有运行完成的`CF`(使用缺省值)
- 业务最终一致性时,能返回就尽量返回有的;对于没有及时返回还在运行中处理的`CF`,结果会写到分布式缓存中避免重复计算,下次就有了
- 这是个常见业务使用模式,`cffu`提供了相应的`mostResultsOfSuccess`方法

> 📔 关于多个`CF`的并发执行策略,可以看看`JavaScript`规范[`Promise Concurrency`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise#promise_concurrency);在`JavaScript`中,`Promise`即对应`CompletableFuture`
>
Expand Down
44 changes: 30 additions & 14 deletions cffu-core/src/main/java/io/foldright/cffu/CffuFactory.java
Original file line number Diff line number Diff line change
Expand Up @@ -228,10 +228,10 @@ public <T> Cffu<T> supplyAsync(Supplier<T> supplier, Executor executor) {
* <p>
* In general, should not use this method in biz code, prefer below factory methods of Cffu:
*
* <ol>
* <ul>
* <li>{@link #runAsync(Runnable)}
* <li>{@link #supplyAsync(Supplier, Executor)}
* </ol>
* </ul>
*
* @see #runAsync(Runnable)
* @see #runAsync(Runnable, Executor)
Expand Down Expand Up @@ -298,25 +298,33 @@ public final <T> Cffu<T>[] toCffuArray(CompletionStage<T>... stages) {
* Cffu({@code Cffu<Void>}), but may be obtained by inspecting them individually.
* If no stages are provided, returns a Cffu completed with the value {@code null}.
* <p>
* if you need the results of given stages, prefer below methods:
* <ol>
* This method is the same as {@link CompletableFuture#allOf(CompletableFuture[])},
* except that the parameter type is more generic {@link CompletionStage} instead of {@link CompletableFuture}.
* <p>
* If you need the results of given stages, prefer below methods:
* <ul>
* <li>{@link #allResultsOf(CompletionStage[])}
* <li>{@link #allTupleOf(CompletionStage, CompletionStage)} /
* {@link #allTupleOf(CompletionStage, CompletionStage, CompletionStage, CompletionStage, CompletionStage)}
* (provided overloaded methods with 2~5 input)
* </ol>
* </ul>
* <p>
* This method is the same as {@link CompletableFuture#allOf(CompletableFuture[])},
* except that the parameter type is more generic {@link CompletionStage} instead of {@link CompletableFuture}.
* If you need the successful results of given stages in the given time, prefer below methods:
* <ul>
* <li>{@link #mostResultsOfSuccess(long, TimeUnit, Object, CompletionStage[])}
* <li>{@link #mostTupleOfSuccess(long, TimeUnit, CompletionStage, CompletionStage)}
* <li>{@link #mostTupleOfSuccess(long, TimeUnit, CompletionStage, CompletionStage, CompletionStage, CompletionStage, CompletionStage)}
* </ul>
*
* @param cfs the stages
* @return a new Cffu that is completed when all the given stages complete
* @throws NullPointerException if the array or any of its elements are {@code null}
* @see #allResultsOf(CompletionStage[])
* @see #allTupleOf(CompletionStage, CompletionStage)
* @see #allTupleOf(CompletionStage, CompletionStage, CompletionStage)
* @see #allTupleOf(CompletionStage, CompletionStage, CompletionStage, CompletionStage)
* @see #allTupleOf(CompletionStage, CompletionStage, CompletionStage, CompletionStage, CompletionStage)
* @see #mostResultsOfSuccess(long, TimeUnit, Object, CompletionStage[])
* @see #mostTupleOfSuccess(long, TimeUnit, CompletionStage, CompletionStage)
* @see #mostTupleOfSuccess(long, TimeUnit, CompletionStage, CompletionStage, CompletionStage, CompletionStage, CompletionStage)
* @see CompletableFutureUtils#allOf(CompletionStage[])
*/
@Contract(pure = true)
Expand Down Expand Up @@ -354,24 +362,32 @@ public final <T> Cffu<List<T>> allResultsOf(CompletionStage<? extends T>... cfs)
* but may be obtained by inspecting them individually.
* If no stages are provided, returns a Cffu completed with the value {@code null}.
* <p>
* This method is the same as {@link #allOf(CompletionStage[])} except for the fast-fail behavior.
* <p>
* If you need the results of given stages, prefer below methods:
* <ol>
* <ul>
* <li>{@link #allResultsOfFastFail(CompletionStage[])}
* <li>{@link #allTupleOfFastFail(CompletionStage, CompletionStage)} /
* {@link #allTupleOfFastFail(CompletionStage, CompletionStage, CompletionStage, CompletionStage, CompletionStage)}
* (provided overloaded methods with 2~5 input)
* </ol>
* </ul>
* <p>
* This method is the same as {@link #allOf(CompletionStage[])} except for the fast-fail behavior.
* If you need the successful results of given stages in the given time, prefer below methods:
* <ul>
* <li>{@link #mostResultsOfSuccess(long, TimeUnit, Object, CompletionStage[])}
* <li>{@link #mostTupleOfSuccess(long, TimeUnit, CompletionStage, CompletionStage)}
* <li>{@link #mostTupleOfSuccess(long, TimeUnit, CompletionStage, CompletionStage, CompletionStage, CompletionStage, CompletionStage)}
* </ul>
*
* @param cfs the stages
* @return a new Cffu that is successful when all the given stages success
* @throws NullPointerException if the array or any of its elements are {@code null}
* @see #allResultsOfFastFail(CompletionStage[])
* @see #allTupleOfFastFail(CompletionStage, CompletionStage)
* @see #allTupleOfFastFail(CompletionStage, CompletionStage, CompletionStage)
* @see #allTupleOfFastFail(CompletionStage, CompletionStage, CompletionStage, CompletionStage)
* @see #allTupleOfFastFail(CompletionStage, CompletionStage, CompletionStage, CompletionStage, CompletionStage)
* @see #mostResultsOfSuccess(long, TimeUnit, Object, CompletionStage[])
* @see #mostTupleOfSuccess(long, TimeUnit, CompletionStage, CompletionStage)
* @see #mostTupleOfSuccess(long, TimeUnit, CompletionStage, CompletionStage, CompletionStage, CompletionStage, CompletionStage)
* @see #allOf(CompletionStage[])
*/
@Contract(pure = true)
Expand Down
Loading

0 comments on commit 8eb1040

Please sign in to comment.