CompletableFuture,main 永远不会退出

nav*_*978 1 java java-8 completable-future

我正在学习 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;

    }



}
Run Code Online (Sandbox Code Playgroud)

(为了运行该代码,您需要“resteasy-client”库)

但我不明白为什么即使收集了所有响应,主要方法也不会终止......

我错过了什么?是否有一些“完整”的方法可以在任何地方调用,如果有的话在哪里?

Mik*_*Hay 5

您的 main 方法已完成,但程序继续运行,因为您创建了其他仍处于活动状态的线程。最好的解决方案是在向 ExecutorService 提交所有任务后调用shutdown 。

或者,您可以创建一个使用线程的 ExecutorService daemon(请参阅Thread 文档),或使用allowedCoreThreadTimeout(true)的 ThreadPoolExecutor ,或者仅在 main 方法末尾调用System.exit 。

  • 除此之外,还有 30 个 `ResteasyClient` 未使用 `close()`d。 (3认同)
  • 我想我明白了......而不是将“Executor”传递给 CompletableFuture,也可以传递“ExecutorService”,就像在它起作用的主方法末尾添加以下代码一样:“allPageContentsFuture.thenRun(() -&gt;executorService.shutdown());" (2认同)