Я изучаю 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»)
Но я не понимаю, почему даже когда все ответы собраны, основной метод не завершается...
Я что-то пропустил? Есть ли какой-то «полный» метод для вызова где угодно, и если да, то где?




Ваш основной метод завершается, но программа продолжает работать, поскольку вы создали другие потоки, которые все еще живы. Лучшее решение — вызвать неисправность в ExecutorService после того, как вы отправите ему все свои задачи.
В качестве альтернативы вы можете создать ExecutorService, который использует потоки daemon (см. Документация по теме), или ThreadPoolExecutor с разрешитьCoreThreadTimeout (истина), или просто вызвать Система.выход в конце основного метода.
Чтобы добавить к этому, есть также 30 ResteasyClients, которые остались un-close()d.
@SpencerPark Спасибо, я изменил код в вопросе, чтобы закрыть ResteasyClients.
Но я все еще не понимаю, как получить доступ к Executor, который создается по умолчанию, и вызвать на нем завершение работы...
Вам не нужно беспокоиться об отключении общего пула, используемого CompletableFutures, это не заблокирует выход программы. Вы явно создаете Executor в верхней части вашей программы, и, как указывает Спенсер, неявно создаете некоторые из них через ResteasyClients. Вы должны закрыть их, чтобы завершить программу.
Думаю, я понял... Вместо того, чтобы передавать «Исполнитель» в CompletableFuture, также можно передать «ExecutorService», например, добавив следующий код в конце основного механизма, который работает: «allPageContentsFuture.thenRun(() ->executorService.shutdown());"
Спасибо за ваш ответ, как я могу автоматически получить доступ к ExecutorService, созданному CompletableFuture?