为什么CompletableFuture.supplyAsync成功随机次数?

我是Java 8中lambdas和异步代码的新手。我不断得到一些奇怪的结果……

我有以下代码:

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 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次。 没有exception抛出。 似乎某些线程处理机制默默地拒绝创建新线程并执行它们的代码,或者线程在没有崩溃程序的情况下静默崩溃。

我还有一个问题,如果我向doPost方法添加比上面显示的更多的function,它会达到一个方法,该方法只是默默地破坏。 我已经尝试在返回语句之前添加一个System.out.println("test") ,但是从不调用它。 循环100次的循环确实运行了100次迭代。

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

我错过了什么? 为什么作为supplyAsync的参数提供的函数运行看似随机的次数?

编辑:只是想指出情况与问题中的情况不完全相同,因为这个问题涉及任意深度嵌套的期货,而且这个问题涉及平行的问题。 然而,他们失败的原因几乎完全相同。 这些案件看起来很明显,值得向我提出不同的问题,但其他人可能不同意……

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

您有以下选择:

  1. 将所有CompletionStage收集到某个数组,然后生成java.util.concurrent.CompletableFuture#allOf() .toCompletableFuture().join() – 这将保证所有阶段在完成join()之后完成

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

     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 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; }