CompleteableFuture Java 8 необычное поведение - PullRequest
1 голос
/ 03 июля 2019

Я заметил несколько необычное поведение с CompleteableFutures в Java 8 с потоковой передачей.

String [] arr = new String[]{"abc", "def", "cde", "ghj"};
        ExecutorService executorService = Executors.newFixedThreadPool(10);
        List<String> lst =
                Arrays.stream(arr)
                        .map(r ->
                                CompletableFuture.supplyAsync(() -> {
                                    try {
                                        Thread.sleep(5000);
                                        return "e";
                                    } catch (Exception e) {
                                        e.printStackTrace();
                                    }
                                    return null;
                                }, executorService)
                        )
                        .map(CompletableFuture::join)
                        .collect(Collectors.toList());

Этот код выше занимает 4 * 5000 = 20 секунд, поэтому это означает, что фьючерсы ждут друг друга.

 String [] arr = new String[]{"abc", "def", "cde", "ghj"};
        ExecutorService executorService = Executors.newFixedThreadPool(10);
        List<CompletableFuture<String>> lst =
                Arrays.stream(arr)
                        .map(r ->
                                CompletableFuture.supplyAsync(() -> {
                                    try {
                                        Thread.sleep(5000);
                                        return "d";
                                    } catch (Exception e) {
                                        e.printStackTrace();
                                    }
                                    return null;
                                }, executorService)
                        )
                        .collect(Collectors.toList());

        List<String> s =
                lst
                        .stream()
                        .map(CompletableFuture::join)
                        .collect(Collectors.toList());

        System.out.println(s);

Этот код, однако, выполняется за 5 секунд, что означает, что фьючерсы работают параллельно.

Что я не понимаю: Во втором примере я получаю список фьючерсов в явном виде,затем выполните объединение, которое занимает 5 секунд, первый пример, через который я продолжаю потоковую передачу, и кажется, что оно ждет.

В чем причина этого?

1 Ответ

1 голос
/ 03 июля 2019

Потоки не обязательно выполняют одну стадию, а затем следующую.Они могут составлять операции в любом порядке по своему выбору.

Так, например,

Arrays.stream(array).map(e -> f(e)).map(e -> g(e)).collect(toList());

может в конечном итоге выполняться так же, как

Arrays.stream(array).map(e -> g(f(e))).collect(toList());

...что привело бы к результатам, которые вы видите: фьючерсы генерируются по одному и сразу включаются, а не генерируются сразу, а затем соединяются.

На самом деле, если вы не делаете что-то асинхронноеобычно более эффективнее делать это вторым способом.Таким образом, потоковая среда не должна хранить все результаты функции f, а затем сохранять все результаты функции g: она может хранить только результаты функции g (f (e)).Каркас потока не может знать, что вы делаете асинхронный код, поэтому он выполняет обычную эффективную работу.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...