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

标签 java asynchronous lambda completable-future

我对 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 次,但出于性能原因而异步执行(以便比执行 100 次同步调用更快地将数据推送到 Web 服务)。

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

我还有一个问题,如果我向 doPost 方法添加比上面显示的更多的功能,它就会达到该方法只是默默地中断的地步。在这种情况下,我尝试在 return 语句之前添加一个 System.out.println("test") ,但它从未被调用。不过,循环 100 次的循环确实运行了 100 次迭代。

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

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

编辑:只是想指出,情况与被标记为可能重复的问题并不完全相同,因为该问题涉及任意深度嵌套的 future ,而这个问题涉及并行那些。然而,他们失败的原因几乎是相同的。这些案例似乎足够明显,值得我单独提出问题,但其他人可能不同意......

最佳答案

默认情况下,CompletableFuture 使用自己的ForkJoinPool.commonPool()(请参阅 CompletableFuture 实现)。这个默认池仅创建守护进程线程,例如如果它们还活着,它们不会阻止主应用程序终止。

您有以下选择:

  1. 将所有 CompletionStage 收集到某个数组,然后制作 java.util.concurrent.CompletableFuture#allOf() .toCompletableFuture().join() - 这将保证在join()

  2. 之后完成所有阶段
  3. *异步操作与您自己的线程池一起使用,该线程池仅包含非守护程序线程,如以下示例所示:

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

关于java - 为什么 CompletableFuture.supplyAsync 会成功随机次数?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42439198/

相关文章:

java - 组合框条目未显示在框架上

c# - 使用 Rx Framework 使用 void AsyncMethod(Action<T>callback) 模式进行异步调用

java - lambda 序列化

c# - 在 C# 中调用具有多个参数的表达式时出现 NullReferenceException

c++ - 传递 std::shared_ptr 作为对 lambda 捕获列表的引用 (C++)

java - 组合的模

java - 在 Tomcat 上运行 GWT 应用程序时出现 StringIndexOutOfBoundsException 错误

java - Maven ClassNotFoundException SpringServletContainerInitializer

c - 将输入重新打印到 C 中的终端

c++ - 跟进: Asynchronous off-screen query performance