当前位置: 首页 > 面试题库 >

为什么CompletableFuture.supplyAsync成功连续随机执行几次?

蒲德曜
2023-03-14
问题内容

我对Java 8中的lambda和异步代码都是陌生的。我不断得到一些奇怪的结果…

我有以下代码:

import java.util.concurrent.CompletableFuture;

public class Program {

    public static void main(String[] args) {
        for (int i = 0; i < 100; i++) {
            String test = "Test_" + i;
            final int a = i;

            CompletableFuture<Boolean> cf = CompletableFuture.supplyAsync(() -> doPost(test));
            cf.thenRun(() -> System.out.println(a)) ;
        }
    }

    private static boolean doPost(String t) {
        System.out.println(t);

        return true;
    }
}

实际的代码要长得多,因为该doPost方法会将一些数据发布到Web服务。但是,我可以使用此基本代码来复制我的问题。

我想让该doPost方法执行100次,但出于性能方面的考虑而异步执行(以便将数据推送到Web服务的速度比执行100次同步调用的速度更快)。

在上面的代码中,“
doPost”方法运行随机次数,但始终不超过20-25次。没有抛出异常。似乎是某种线程处理机制无声地拒绝创建新线程并执行其代码,或者这些线程无声地崩溃而没有崩溃程序。

我还遇到一个问题,如果我向该doPost方法添加了比上图所示更多的功能,则会达到该方法无提示中断的地步。System.out.println("test")在这种情况下,我曾尝试在return语句前添加一个权利,但从未调用过它。但是,循环100次的循环会运行100次迭代。

至少可以这样说,这种行为令人困惑。

我想念什么?为什么提供该函数作为参数来supplyAsync运行看似随机的次数?

编辑:只是想指出情况与该问题可能被标记为重复的问题并不完全相同,因为该问题涉及任意深度嵌套的期货,而这个问题涉及并行的期货。
但是,它们失败的原因实际上是相同的。这些案件似乎足够独特,可以向我提出单独的问题,但其他人可能会不同意…


问题答案:

默认情况下CompletableFuture使用自己的 ForkJoinPool.commonPool()
(请参阅CompletableFuture实现)。并且该默认池仅创建
守护程序 线程,例如,如果它们仍然存在,它们将不会阻止主应用程序终止。

您有以下选择:

  1. 将所有内容收集CompletionStage到某个数组中,然后进行制作-这将确保在执行 join() 之后所有阶段都已完成java.util.concurrent.CompletableFuture#allOf().toCompletableFuture().join() __

  2. 对您自己的仅包含 非守护程序 线程的线程池使用 * Async 操作,如以下示例所示: __

        public static void main(String[] args) throws InterruptedException {
        ExecutorService pool = Executors.newFixedThreadPool(10, r -> {
            Thread t = new Thread(r);
            t.setDaemon(false); // must be not daemon
            return t;
        });

        for (int i = 0; i < 100; i++) {
            final int a = i;

            // the operation must be Async with our thread pool
            CompletableFuture<Boolean> cf = CompletableFuture.supplyAsync(() -> doPost(a), pool);
            cf.thenRun(() -> System.out.printf("%s: Run_%s%n", Thread.currentThread().getName(), a));
        }

        pool.shutdown(); // without this the main application will be blocked forever
    }

    private static boolean doPost(int t) {
        System.out.printf("%s: Post_%s%n", Thread.currentThread().getName(), t);

        return true;
    }


 类似资料:
  • 问题内容: 我必须为数组中每个项目的某些异步任务打电话给Promise,但我想串行执行这些任务。 Promise.all仅在具有合并了诺言列表但不按顺序调用它们的新诺言时才有用。 我如何在没有第三方库(例如Q,bluebird …)的情况下使用标准的Promise API来实现此目标。 问题答案: 您将诺言与返回另一个诺言的回调一起使用。因此,假设您有三个函数a,b和c都返回了诺言。您可以像这样链

  • C 11支持通过<代码> 我看过多本书,其中提到持续构建和销毁std::random\u device、std::uniform\u int\u distribution非常昂贵 为什么创建/销毁这些对象的成本很高?这里的昂贵到底是什么意思?它在执行速度、可执行文件大小或其他方面是否昂贵? 有人能解释一下吗?

  • 据我所知,promise是可以解析()或拒绝()的东西,但我惊讶地发现,promise中的代码在调用解析或拒绝后仍继续执行。 我认为resolve或reject是exit或return的异步友好版本,它将停止所有立即的函数执行。 有人能解释一下为什么下面的示例有时在解析调用后显示console.log的背后思想吗: 杰斯宾

  • 问题内容: 我正在使用Ubuntu 14.04 64位。这是我的C ++代码,以了解如何使用内存。 这是我的输出: 我希望操作系统会连续分配内存。因此,ptr [0] [0]将位于0x1195020而不是0x1195030!OS在0x1195020-0x119502F,0x1195038-0x0x119504F上做什么用? 问题答案: 因为: 在分配的内存的每个块的开始和结尾处都有一些空间通常用于

  • 我是javascript新手,这可能是一个简单的问题。。。 我在这里所做的是修改div(#box)的css样式,这取决于你所在页面的位置( 我试图实现的是向#box添加多个css更改,并每次执行一个随机更改。例如,每次从最顶端滚动通过200,div的显示高度为:绿色背景为“100px”,蓝色背景为“200px”,或红色背景为“300px”。希望这有意义。。。。

  • 我比较了CompletableFuture.SupplyAsync()在以下两种情况下的行为:我设置了一个自定义ExecutorService,或者我希望我的供应商由默认的executor(如果没有指定)执行,这两种情况是forkJoinPool.commonpool() 完成了!! 所以“done”会在主执行结束后打印出来。 但如果我用: