在supplyAsync阻塞主线程之后使用thenAccept [英] Using thenAccept after supplyAsync blocks the main thread
问题描述
我正在开发一个与其他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屋!