CompletableFuture, main никогда не выходит

Я изучаю Java 8 и более подробно "CompletableFuture". После этого интересного урока: https://www.callicoder.com/java-8-completablefuture-tutorial/

Я написал следующий класс Java:

package parallels;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
import java.util.stream.Collectors;

import javax.ws.rs.client.ClientRequestFilter;
import javax.ws.rs.core.Response;

import org.jboss.resteasy.client.jaxrs.ResteasyClient;
import org.jboss.resteasy.client.jaxrs.ResteasyClientBuilder;
import org.jboss.resteasy.client.jaxrs.ResteasyWebTarget;




public class Test {
    private static final String USER_AGENT = "Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:56.0) Gecko/20100101 Firefox/56.0";
    private static final Executor executor = Executors.newFixedThreadPool(100);

    public static void main(String[] args) {

        List<String> webPageLinks= new ArrayList<String>();
        for (int i=0;i<30;i++) {
            webPageLinks.add("http://jsonplaceholder.typicode.com/todos/1");
        }

        // Download contents of all the web pages asynchronously
        List<CompletableFuture<String>> pageContentFutures = webPageLinks.stream()
                .map(webPageLink -> downloadWebPage(webPageLink))
                .collect(Collectors.toList());


        // Create a combined Future using allOf()
        CompletableFuture<Void> allFutures = CompletableFuture.allOf(
                pageContentFutures.toArray(new CompletableFuture[pageContentFutures.size()])
                );


        // When all the Futures are completed, call `future.join()` to get their results and collect the results in a list -
        CompletableFuture<List<String>> allPageContentsFuture = allFutures.thenApply(v -> {
            return pageContentFutures.stream()
                    .map(pageContentFuture -> pageContentFuture.join())
                    .collect(Collectors.toList());
        });


    }



    private static CompletableFuture<String> downloadWebPage(String pageLink) {
        CompletableFuture<String> completableFuture = CompletableFuture.supplyAsync(() -> getRequest(pageLink),executor);
        return completableFuture;
    } 

    public static String getRequest(String url) {
        System.out.println("getRequest");
        String resp =null;
        try {
            ResteasyClient client = new ResteasyClientBuilder().build();
            ResteasyWebTarget target = client.target(url);
            target.register((ClientRequestFilter) requestContext -> {
                requestContext.getHeaders().add("User-Agent",USER_AGENT);
            });
            Response response = target.request().get();
            resp= response.readEntity(String.class);
            System.out.println(resp);
            response.close();  
            client.close();

            System.out.println("End getRequest");
        }catch(Throwable t) {
            t.printStackTrace();
        }




        return resp;

    }



}

(Чтобы запустить этот код, вам нужна библиотека «resteasy-client»)

Но я не понимаю, почему даже когда все ответы собраны, основной метод не завершается...

Я что-то пропустил? Есть ли какой-то «полный» метод для вызова где угодно, и если да, то где?

Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
0
0
756
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Ваш основной метод завершается, но программа продолжает работать, поскольку вы создали другие потоки, которые все еще живы. Лучшее решение — вызвать неисправность в ExecutorService после того, как вы отправите ему все свои задачи.

В качестве альтернативы вы можете создать ExecutorService, который использует потоки daemon (см. Документация по теме), или ThreadPoolExecutor с разрешитьCoreThreadTimeout (истина), или просто вызвать Система.выход в конце основного метода.

Спасибо за ваш ответ, как я могу автоматически получить доступ к ExecutorService, созданному CompletableFuture?

navy1978 05.06.2019 18:27

Чтобы добавить к этому, есть также 30 ResteasyClients, которые остались un-close()d.

SpencerPark 05.06.2019 18:27

@SpencerPark Спасибо, я изменил код в вопросе, чтобы закрыть ResteasyClients.

navy1978 05.06.2019 18:29

Но я все еще не понимаю, как получить доступ к Executor, который создается по умолчанию, и вызвать на нем завершение работы...

navy1978 05.06.2019 18:30

Вам не нужно беспокоиться об отключении общего пула, используемого CompletableFutures, это не заблокирует выход программы. Вы явно создаете Executor в верхней части вашей программы, и, как указывает Спенсер, неявно создаете некоторые из них через ResteasyClients. Вы должны закрыть их, чтобы завершить программу.

MikeFHay 05.06.2019 18:34

Думаю, я понял... Вместо того, чтобы передавать «Исполнитель» в CompletableFuture, также можно передать «ExecutorService», например, добавив следующий код в конце основного механизма, который работает: «allPageContentsFuture.thenRun(() ->executorService.shutdown(‌​));"

navy1978 05.06.2019 18:37

Другие вопросы по теме