简体   繁体   English

CompletableFuture显示不一致的线程行为

[英]CompletableFuture showing inconsistent threading behavior

CompletableFuture's documentation specifies the following behavior for asynchronous execution: CompletableFuture的文档为异步执行指定了以下行为:

All async methods without an explicit Executor argument are performed using the ForkJoinPool#commonPool() (unless it does not support a parallelism level of at least two, in which case, a new Thread is created to run each task). 所有没有显式Executor参数的异步方法都是使用ForkJoinPool#commonPool()执行的(除非它不支持并行度至少为2,在这种情况下,将创建一个新的Thread来运行每个任务)。 To simplify monitoring, debugging, and tracking, all generated asynchronous tasks are instances of the marker interface AsynchronousCompletionTask. 为了简化监视,调试和跟踪,所有生成的异步任务都是标记接口AsynchronousCompletionTask的实例。

However, the behavior of synchronous (or at least the non async) methods remain unclear. 但是,同步(或至少是非异步)方法的行为仍然不清楚。 In most situations, the code executes with the original thread, like so: 在大多数情况下,代码使用原始线程执行,如下所示:

Thread thread = Thread.currentThread();
CompletableFuture.runAsync(() -> {
        // Should run on the common pool - working as expected
        assert thread != Thread.currentThread();
}).thenRun(() -> {
        // Returns to running on the thread that launched.. sometimes?
        assert thread == Thread.currentThread();
}).join();

However, repetition of this test yields inconsistent results, as the second block of code sometimes uses the common pool instead. 但是,重复此测试会产生不一致的结果,因为第二个代码块有时会使用公共池。 What is the intended behavior in this situation? 在这种情况下的预期行为是什么?

After looking at the OpenJDK implementation of CompletableFuture here , it smells like you're encountering a sort of race condition. 看着在OpenJDK执行CompletableFuture后在这里 ,它闻起来像你遇到一种竞争状态。 Suppose we're doing something along the lines of runAsync(a).thenRun(b) . 假设我们正在执行类似runAsync(a).thenRun(b) If a finishes execution on the common pool thread before thenRun(b) gets called on the current thread, then b is run immediately on the current thread once thenRun(b) finally gets called. 如果a以前在公共池线程完成执行thenRun(b)被称为当前线程上,然后b立即在当前线程上运行一次thenRun(b)终于被调用。 On the other hand, if thenRun(b) is called before a finishes on the other thread, then b is run on the same thread as a once a finally finishes. 在另一方面,如果thenRun(b)之前被调用a其他线程上完成,那么b是相同的线程上运行作为a曾经a终于完成。

It's sort of like this: 有点像这样:

class CompletableFuture:
  function runAsync(a):
    function c():
      run a
      for each b in the handler stack:
        run b
    run c on a different thread
    return future representing c
  function thenRun(b):
    if c is done:
      run b
    else:
      put b in c's handler stack

Clearly, b is run in c 's thread if thenRun is called before a finishes. 显然, b在运行c的线程,如果thenRun之前被调用a结束。 Otherwise, b is run in the current thread. 否则, b在当前线程中运行。

If you want more consistent behaviour in terms of which thread runs what, you should try using CompletableFuture#thenRunAsync , which guarantees the handler is executed in some particular executor pool. 如果要在哪个线程运行什么方面获得更一致的行为,则应尝试使用CompletableFuture#thenRunAsync ,以确保处理程序在某些特定的执行程序池中执行。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM