안녕하세요.ExecutorService가 중지되지 않습니다. 실행중인 다른 작업에서 새 작업을 실행할 때
웹 크롤러 프로젝트에 방해물 문제가 있습니다. 논리가 간단합니다. 먼저 Runnable
하나를 만들고 html 문서를 다운로드하고 모든 링크를 스캔 한 다음 모든 자금 지원 링크에 새로운 Runnable
개체를 만듭니다. 새로운 각각의 Runnable
을 생성하면 각 링크에 대해 새로운 Runnable
개체가 만들어지고 실행됩니다.
문제는 ExecutorService
이 중지되지 않습니다.
CrawlerTest.java
public class CrawlerTest {
public static void main(String[] args) throws InterruptedException {
new CrawlerService().crawlInternetResource("https://jsoup.org/");
}
}
CrawlerService.java
import java.io.IOException;
import java.util.Collections;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
public class CrawlerService {
private Set<String> uniqueUrls = Collections.newSetFromMap(new ConcurrentHashMap<String, Boolean>(10000));
private ExecutorService executorService = Executors.newFixedThreadPool(8);
private String baseDomainUrl;
public void crawlInternetResource(String baseDomainUrl) throws InterruptedException {
this.baseDomainUrl = baseDomainUrl;
System.out.println("Start");
executorService.execute(new Crawler(baseDomainUrl)); //Run first thread and scan main domain page. This thread produce new threads.
executorService.awaitTermination(10, TimeUnit.MINUTES);
System.out.println("End");
}
private class Crawler implements Runnable { // Inner class that encapsulates thread and scan for links
private String urlToCrawl;
public Crawler(String urlToCrawl) {
this.urlToCrawl = urlToCrawl;
}
public void run() {
try {
findAllLinks();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
private void findAllLinks() throws InterruptedException {
/*Try to add new url in collection, if url is unique adds it to collection,
* scan document and start new thread for finded links*/
if (uniqueUrls.add(urlToCrawl)) {
System.out.println(urlToCrawl);
Document htmlDocument = loadHtmlDocument(urlToCrawl);
Elements findedLinks = htmlDocument.select("a[href]");
for (Element link : findedLinks) {
String absLink = link.attr("abs:href");
if (absLink.contains(baseDomainUrl) && !absLink.contains("#")) { //Check that we are don't go out of domain
executorService.execute(new Crawler(absLink)); //Start new thread for each funded link
}
}
}
}
private Document loadHtmlDocument(String internetResourceUrl) {
Document document = null;
try {
document = Jsoup.connect(internetResourceUrl).ignoreHttpErrors(true).ignoreContentType(true)
.userAgent("Mozilla/5.0 (Windows NT 6.1; WOW64; rv:48.0) Gecko/20100101 Firefox/48.0")
.timeout(10000).get();
} catch (IOException e) {
System.out.println("Page load error");
e.printStackTrace();
}
return document;
}
}
}
이 응용 프로그램은 모든 고유 링크 jsoup.org를 스캔하는 데 약 20 초 필요합니다. 그러나 그것은 단지 10 분을 기다린다. executorService.awaitTermination(10, TimeUnit.MINUTES);
그리고 난 죽은 메인 쓰레드를보고 여전히 실행 중이다.
어떻게 제대로 ExecutorService
작업을 강제로?
문제는 executorService.execute가 메인 스레드 대신 다른 태스크 내부에서 호출된다는 것입니다.
try catch에서'executorService'를 처리하고'finally' 블록에'executorService.shutdown();'이라고 써주십시오. [참고] (https://docs.oracle.com/javase/7/docs/api/java/util/concurrent/ExecutorService.html) – Imran
@Imran 작동하지 않습니다. 주 스레드가 죽을 때까지 10 분을 기다립니다. 문제는 executorService.execute가 메인 스레드 대신 다른 태스크 내부에서 호출된다는 것입니다. – Redeemer