问题
I'm learning Java 8 and more in detail the "CompletableFuture". Following this interesting tutorial: https://www.callicoder.com/java-8-completablefuture-tutorial/
I wrote the following Java class :
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;
}
}
(In order to run that code you need "resteasy-client" library)
But I don't understand why even when all the responses are collected the main method doesn't terminate...
Did I miss something? Is there some "complete" method to call anywhere, and if yes where?
回答1:
Your main method completes, but the program continues running as you have created other threads which are still alive. The best solution is to call shutdown on your ExecutorService once you've submitted all your tasks to it.
Alternatively you could create an ExecutorService which uses daemon
threads (see the Thread documentation), or a ThreadPoolExecutor with allowCoreThreadTimeout(true), or just call System.exit at the end of your main method.
来源:https://stackoverflow.com/questions/56464403/completablefuture-main-never-exits