CompletableFuture :: join并不总是完成所有指令

时间:2019-01-22 15:53:45

标签: java multithreading completable-future

我一直在使用Java的CompletableFuture进行异步HTTP调用,以了解它与传统的同步(从而阻塞)调用相比有多快。 结果是压倒性的:使用CompletableFuture通常可使代码执行20次HTTP调用的速度提高8倍。

数字20不是任意的:我之所以选择它,是因为我想先耗尽所有12个CPU内核,因此一旦忙碌的内核开始释放出来,它就可以开始发出新请求(如果我错了,请纠正我,但是CompletableFuture使用Runtime.getRuntime().availableProcessors()中可用的内核数量,因此并行进行20次调用就足以用完所有可用的内核并排队等待请求。)

每次执行时,我将结果存储在给定的List中,然后在为每个创建的Future调用CompletableFuture :: join之后简单地声明此List的大小。

我面临的问题是,在大多数情况下,列表的大小在17-19之间,而不是等于20。我的测试以4:5的比率失败(这显然在计算机之间会有所不同)。

为了简单起见,我创建了以下代码(出于简单起见,并且由于这是一个Spring Project,我决定使用RestTemplate进行HTTP调用):

import org.junit.Before;
import org.junit.Test;
import org.springframework.http.ResponseEntity;
import org.springframework.web.client.RestTemplate;

import java.net.URI;
import java.util.ArrayList;
import java.util.Collection;
import java.util.concurrent.CompletableFuture;
import java.util.stream.IntStream;

import static org.junit.Assert.*;

public class CompletableFutureTest {

    private Collection<CompletableFuture<Void>> futures;

    private Collection<ResponseEntity<String>> results;

    private final RestTemplate restTemplate = new RestTemplate();

    @Before
    public void setup() {
        this.futures = new ArrayList<>();
        this.results = new ArrayList<>();
    }

    @Test
    public void asyncHttpCallsTest() {
        IntStream.range(0, 20).forEach(i -> {
            this.futures.add(CompletableFuture.runAsync(() -> {
                this.results.add(this.restTemplate.getForEntity(URI.create("http://www.google.com"), String.class));
            }));
        });

        this.futures.forEach(CompletableFuture::join);

        Assert.assertEquals(20, this.results.size());
    }

}

我确信CompletableFuture是可靠的,所以我敢打赌,由于缺乏对该API的了解,我缺少了一些东西。

谢谢!

0 个答案:

没有答案