我试图使用 EA 的 async/await 库来模仿 Java 中 Javascript 的单线程异步编程( ea-async )。这主要是因为我的程序中没有持久的 CPU 密集计算,并且我想用 Java 编写单线程无锁代码。
ea-async 库严重依赖于 Java 中的 CompletableFuture,并且在 Java 底层似乎使用 ForkJoinPool 来运行异步回调。这使我进入多线程环境,因为我的 CPU 是多核的。似乎对于每个 CompletableFuture 任务,我都可以使用我的自定义线程池执行器提供异步。我可以供应Executors.newSingleThreadExecutor()
为此,但我需要一种全局设置的方法,以便所有 CompletableFuture 都将在单个 JVM 进程中使用此执行器。我该怎么做?
最佳答案
ea-async library heavily relies on the CompletableFuture in Java and underneath Java seems to use
ForkJoinPool
to run the async callbacks.
这是 CompleteableFuture
的默认行为:
All async methods without an explicit
Executor
argument are performed using theForkJoinPool.commonPool()
(unless it does not support a parallelism level of at least two, in which case, a newThread
is created to run each task). This may be overridden for non-static methods in subclasses by defining methoddefaultExecutor()
.
这是该类的定义特征,因此,如果您使用类 CompleteableFuture
,而不是子类,并且在未显式指定 Executor
的情况下生成实例,那么您将获得 ForkJoinPool
。
当然,如果您可以控制提供给 ea-async 的 CompletableFuture
,那么您可以选择提供定义 defaultExecutor()
的子类实例,无论您喜欢什么。或者,您可以通过静态工厂方法创建 CompleteableFuture
对象,这些方法允许您显式指定要使用的 Executor
,例如 runAsync(Runnable, Executor)
.
但这可能不是您真正想做的。
如果您使用只有一个线程的执行器,那么您的任务可以相对于提交它们的线程异步执行,是的,但它们将相对于彼此进行序列化。您确实只有一个线程在处理它们,但它会随时处理特定的线程,只坚持该线程直到完成,无论响应实际到达的顺序如何。如果这令人满意,那么就不清楚为什么需要异步操作。
This puts me into multi threaded environment as my CPU is multi-core.
无论您的 CPU 有多少个核心,它都会让您处于多个线程中。这就是 Executor 的作用,甚至是 Executors.newSingleThreadExecutor() 的作用。这就是它们提供的“异步”的意义。
如果我理解正确的话,您会希望使用一个线程将 I/O 复用到多个远程 Web 应用程序。这就是 java.nio.channels.Selector 的用途,但使用它通常需要您自己管理 I/O 操作或使用旨在与选择器互操作的接口(interface)。如果您被锁定到无法使用选择器
的第三方接口(interface),那么多线程和多处理是您唯一可行的选择。
在您写的评论中:
I'm starting to think maybe BlockingQueue might do the job in consolidating all API responses into one queue as tasks where a single thread will work on them.
再说一遍,我不认为您想要随之而来的一切,如果您确实想要,那么我不明白为什么同步工作不是比异步工作更好、更容易。
关于java - 如何为所有 CompletableFuture 全局设置线程池,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55911218/