为什么 CompletableFuture.supplyAsync 成功的次数是随机的? [英] Why is CompletableFuture.supplyAsync succeeding a random number of times?

查看:25
本文介绍了为什么 CompletableFuture.supplyAsync 成功的次数是随机的?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I'm new to both lambdas and asynchronous code in Java 8. I keep getting some weird results...

我有以下代码:

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 服务.但是,我可以用这个简单的代码复制我的问题.

The actual code is a lot longer, as the doPost method will post some data to a web service. However, I'm able to replicate my issue with this bare-bones code.

我想让 doPost 方法执行 100 次,但出于性能原因异步执行(为了将数据推送到 Web 服务的速度比执行 100 次同步调用更快).

I want to have the doPost method execute 100 times, but asynchronously for performance reasons (in order to push data to the web service faster than doing 100 synchronous calls would be).

在上面的代码中,doPost"方法运行了随机次数,但始终不超过 20-25 次.没有抛出异常.似乎是某些线程处理机制默默地拒绝创建新线程并执行它们的代码,或者线程在不使程序崩溃的情况下默默地崩溃.

In the code above, the ´doPost´ method is run a random amount of times, but always no more than 20-25 times. There are no exceptions thrown. It seems that either some thread handling mechanism is silently refusing to create new threads and execute their code, or the threads are silently crashing without crashing the program.

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

I also have an issue where, if I add more functionality to the doPost method than shown above, it reaches a point where the method simply silently breaks. I've tried adding a System.out.println("test") right before the return statement in that case, but it is never called. The loop which loops 100 times does run 100 iterations though.

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

This behaviour is confusing, to say the least.

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

What am I missing? Why is the function supplied as an argument to supplyAsync run a seemingly random number of times?

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

推荐答案

默认 CompletableFuture 使用自己的 ForkJoinPool.commonPool()(参见 CompletableFuture 实现).并且这个默认池只创建daemon 线程,例如如果它们还活着,它们不会阻止主应用程序终止.

By default CompletableFuture uses own ForkJoinPool.commonPool() (see CompletableFuture implementation). And this default pool creates only daemon threads, e.g. they won't block the main application from terminating if they still alive.

您有以下选择:

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

  1. Collect all CompletionStage to some array and then make java.util.concurrent.CompletableFuture#allOf().toCompletableFuture().join() - this will guarantee all the stages are completed before going after join()

*Async 操作与您自己的线程池一起使用,该线程池仅包含非守护进程 线程,如下例所示:

Use *Async operations with your own thread pool which contains only non-daemon threads, like in the following example:

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

这篇关于为什么 CompletableFuture.supplyAsync 成功的次数是随机的?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆