在supplyAsync阻塞主线程之后使用thenAccept [英] Using thenAccept after supplyAsync blocks the main thread

查看:1576
本文介绍了在supplyAsync阻塞主线程之后使用thenAccept的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在开发一个与其他Web应用程序通信的Web应用程序.我的系统有时会向其他系统发送HTTP请求作为通知.由于它们的响应对我来说不是必需的,因此我使用Java 8 CompletableFuture supplyAsync发送请求,并使用thenAccept打印它们的响应,这样我的主线程就不会被阻塞.但是,我发现CompletableFuture函数链每次大约花费100到200毫秒,这使我感到困惑,因为从我的理解来看,thenAccept()应该在与supplyAsync()相同的线程中运行.

I am developing a web application which communicates with other web applications. From time to time, my system sends HTTP request as notification to other systems. Since their responses are not essential to me, I send the requests with Java 8 CompletableFuture supplyAsync and prints their responses with thenAccept so that my main thread will not get blocked. However, I found the CompletableFuture function chains took around 100 to 200 ms each time, which confused me because from my understanding thenAccept() should run in the same thread with supplyAsync()'s.

我用以下代码嘲笑了我的过程

I mocked my process with below codes

public static void run() {
    long start = System.currentTimeMillis();
    log.info("run start -> " + new Timestamp(start));
    CompletableFuture.supplyAsync(() -> {
        try {
            Thread.sleep(500);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return 42;
    }).thenAccept(res -> log.info("run result -> " + res + ", time -> " + new Timestamp(System.currentTimeMillis())));
    log.info("run duration ->" + (System.currentTimeMillis() - start));
}

public static void runAsync() {
    long start = System.currentTimeMillis();
    log.info("runAsync start -> " + new Timestamp(start));
    CompletableFuture.supplyAsync(() -> {
        try {
            Thread.sleep(500);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return 42;
    }).thenAcceptAsync(res -> log.info("runAsync result -> " + res + ", time ->" + new Timestamp(System.currentTimeMillis())));
    log.info("runAsync duration ->" + (System.currentTimeMillis() - start));
}

public static void main(String[] args) throws InterruptedException {
    Test.run();
    Test.runAsync();
    Thread.sleep(1000);
}

run()方法将thenAccept()与supplyAsync()一起使用,而runAsync()使用thenAcceptAsync().我期望它们都只需要几毫秒的时间.但是,实际输出是:

the run() method uses thenAccept() with supplyAsync() while runAsync() uses thenAcceptAsync(). I expected both of them should take just a few milliseconds. However, the real outputs are:

10:04:54.632 [main] INFO Test - run start -> 2017-12-08 10:04:54.622
10:04:54.824 [main] INFO Test - run duration ->202
10:04:54.824 [main] INFO Test - runAsync start -> 2017-12-08 10:04:54.824
10:04:54.826 [main] INFO Test - runAsync duration ->2
10:04:55.333 [ForkJoinPool.commonPool-worker-1] INFO Test - run result -> 42, time -> 2017-12-08 10:04:55.333
10:04:55.333 [ForkJoinPool.commonPool-worker-3] INFO Test - runAsync result -> 42, time ->2017-12-08 10:04:55.333

我们可以看到run()花费202毫秒,这是runAsync()持续时间(仅使用2毫秒)的100倍.

We can see run() takes 202 ms which is 100 times of the duration of runAsync() which uses only 2 ms.

我不知道202毫秒的开销是从哪里来的,而且显然不是供应500毫秒的supplyAysnc()中的lambda函数.

I don't understand where is the 202 ms overhead comes from, and obviously it is not the lambda function in supplyAysnc() which sleeps 500 ms.

任何人都可以解释run()方法为何会阻塞,并且我应该始终在thenAccept()上使用thenAcceptAsync()吗?

Could anyone explain why the run() method blocks, and should I always use thenAcceptAsync() over thenAccept() ?

非常感谢.

推荐答案

200毫秒是线程池及其支持的所有类的启动时间.

The 200 ms are startup time for the thread pool and all the classes supporting it.

如果您在主类中交换语句,这将变得显而易见:

It becomes obvious if you swap the statements in your main class:

public static void main(String[] args) throws InterruptedException {
    Test.runAsync();
    Test.run();
    Thread.sleep(1000);
}

现在Test.runAsync();是需要200毫秒的呼叫,而Test.run();则需要2毫秒完成

now Test.runAsync(); is the call that needs 200 ms and Test.run(); completes in 2 ms

这篇关于在supplyAsync阻塞主线程之后使用thenAccept的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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