#multithreading #jsoup #threadpool #executorservice
#многопоточность #jsoup #пул потоков #executorservice
Вопрос:
Я пытаюсь добавить, чтобы установить некоторые объекты, которые я получаю из каждой ссылки. Но объекты не добавляются. Я получаю пустой список. Документ — объект jsoup. Что я делаю не так? Спасибо.
public void spinOffThreadsToGetPages() {
Set<WebPage> webPages = new HashSet<>();
ExecutorService executor = Executors.newFixedThreadPool(10);
for (String link : links) {
executor.submit(() -> addWebPagesToSet(webPages, link));
}
executor.shutdown();
}
private void addWebPagesToSet(Set<WebPage> webPages, String link) {
Document document = getDocument(link);
if (document == null) {
return;
}
WebPage webPage = new WebPage(document.title(), link, document.body().text());
webPages.add(webPage);
}
Ответ №1:
Вы не делаете ничего плохого. Программа запускает потоки, затем вы вызываете ExecutorService::shutdown
. Завершение работы происходит только после завершения всех потоков, но выполнение продолжается, не блокируя выполнение потоков. Если вы распечатаете результаты по мере их возврата, вы получите выходные данные. Если вы попытаетесь распечатать результаты, как только потоки будут отправлены, но еще не завершены, вы ничего не получите обратно.
Попробуйте это:
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import java.io.IOException;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class MultiThreadedGet {
public static void main(String[] args) throws InterruptedException {
Set<WebPage> webPages = new HashSet<>();
ExecutorService executor = Executors.newFixedThreadPool(10);
Map<String, Document> results = new HashMap<>();
List<String> links = Arrays.asList("https://jsoup.org/cookbook/extracting-data/working-with-urls",
"https://news.ycombinator.com/",
"https://www.spectacleapp.com/",
"https://gradle.org/releases/");
for (String link : links) {
executor.submit(() -> {
try {
addWebPagesToSet(webPages, link);
} catch (IOException e) {
e.printStackTrace();
}
});
}
// executor.awaitTermination(30, TimeUnit.SECONDS);
executor.shutdown();
// premature call to print incompleted thread results
for (WebPage webPage : webPages) {
// You won't see this as the threads take some time to complete.
System.out.println("Premature call: " webPage.toString());
}
}
private static void addWebPagesToSet(Set<WebPage> webPages, String link) throws IOException {
Document document = Jsoup.connect(link).get();
if (document == null) {
return;
}
WebPage webPage = new WebPage(document.title(), link, document.body().text());
webPages.add(webPage);
System.out.println("WebPage Result: " webPage.toString());
}
}
class WebPage {
private String title;
private String link;
private String text;
public WebPage(String title, String link, String text) {
this.title = title;
this.link = link;
this.text = text;
}
public String getTitle() {
return title;
}
public String getLink() {
return link;
}
public String getText() {
return text;
}
@Override
public String toString() {
return "title='" title '''
", link='" link '''
", text='" text.substring(0, 25) ''';
}
}
Вывод
WebPage Result: title='Gradle | Releases', link='https://gradle.org/releases/', text='Have you checked out the '
WebPage Result: title='Spectacle', link='https://www.spectacleapp.com/', text='Move and resize windows w'
WebPage Result: title='Hacker News', link='https://news.ycombinator.com/', text='Hacker News new | past | '
WebPage Result: title='Working with URLs: jsoup Java HTML parser', link='https://jsoup.org/cookbook/extracting-data/working-with-urls', text='jsoup News Bugs Discussio'
Если вам нужно дождаться завершения потоков, прежде чем продолжить, вы можете использовать:
executor.awaitTermination(30, TimeUnit.SECONDS);
который заблокирует выполнение текущего потока, чтобы вы могли продолжить с завершенными результатами.
Комментарии:
1. Большое спасибо, это действительно отличный совет. Я должен внести некоторые изменения, чтобы получить результаты, потому что, если бы у меня было много ссылок, 30 секунд было недостаточно. Но вы указываете решение.
2. Я думаю, что CountDownLatch поможет мне без получения результатов в будущем.