2012-01-06 12 views
0

指定された数のページからリンクコレクタをプログラミングしています。効率を上げるため、固定サイズのThreadPoolを使用しています。私はマルチスレッド領域の初心者であるため、いくつかの問題の修正に問題があります。ですから、私の考えは、すべてのスレッドが同じことをしているということです。ページに接続してすべてのURLを収集します。その後、次のスレッドのためにURLにキューが追加されます。スレッドプールを使用してWebページからリンクを収集するjava

しかし、これは機能しません。最初に、baseurlを分析し、そこからurlを追加します。しかし、最初はLinksToVisit.add(baseurl)でのみ実行してスレッドプールで実行したいが、常にポーリングキューとスレッドは何も新しいものを追加しないため、キューの一番上にnull.Andがわからない:(

ArrayBlockingQueueでそれをやろうとしましたが、成功しませんでした。ベースURLを解析して修正するのは良い解決策ではありません。 。。。道や重要な何かが欠けているHTMLパーサとして私が使用していJsoup答えてくれてありがとうを

ソース(削除不要なメソッド):

package collector; 
import java.io.File; 
import java.io.FileNotFoundException; 
import java.io.IOException; 
import java.text.DecimalFormat; 
import java.util.Iterator; 
import java.util.Map; 
import java.util.Scanner; 
import java.util.Map.Entry; 
import java.util.concurrent.*; 
import org.jsoup.Jsoup; 
import org.jsoup.nodes.Document; 
import org.jsoup.nodes.Element; 
import org.jsoup.select.Elements; 


public class Collector { 

private String baseurl; 
private int links; 
private int cvlinks; 
private double time; 
private int chcount; 
private static final int NTHREADS = Runtime.getRuntime().availableProcessors()*2; 
private ConcurrentLinkedQueue<String> LinksToVisit = new ConcurrentLinkedQueue<String>(); 
private ConcurrentSkipListMap<String, Double> SortedCharMap = new ConcurrentSkipListMap<String, Double>(); 
private ConcurrentHashMap<String, Double> CharMap = new ConcurrentHashMap<String, Double>(); 

public Collector(String url, int links) { 
    this.baseurl = url; 
    this.links = links; 
    this.cvlinks = 0; 
    this.chcount = 0; 

    try { 
     Document html = Jsoup.connect(url).get(); 

     if(cvlinks != links){ 
      Elements collectedLinks = html.select("a[href]"); 
      for(Element link:collectedLinks){ 
       if(cvlinks == links) break; 
       else{ 
        String current = link.attr("abs:href"); 
        if(!current.equals(url) && current.startsWith(baseurl)&& !current.contains("#")){ 
         LinksToVisit.add(current); 
         cvlinks++; 
        } 
       } 
      } 
     } 

     AnalyzeDocument(html, url); 
    } catch (IOException e) { 
     e.printStackTrace(); 
    } 
    CollectFromWeb(); 
} 

private void AnalyzeDocument(Document doc,String url){ 
    String text = doc.body().text().toLowerCase().replaceAll("[^a-z]", "").trim(); 
    chcount += text.length(); 
    String chars[] = text.split(""); 
    CharCount(chars); 

} 
private void CharCount(String[] chars) { 
    for(int i = 1; i < chars.length; i++) { 
     if(!CharMap.containsKey(chars[i])) 
      CharMap.put(chars[i],1.0); 
     else 
      CharMap.put(chars[i], CharMap.get(chars[i]).doubleValue()+1); 
    } 
} 

private void CollectFromWeb(){ 
    long startTime = System.nanoTime(); 
    ExecutorService executor = Executors.newFixedThreadPool(NTHREADS); 
    CollectorThread[] workers = new CollectorThread[this.links]; 
    for (int i = 0; i < this.links; i++) { 
     if(!LinksToVisit.isEmpty()){ 
      int j = i+1; 
      System.out.println("Collecting from "+LinksToVisit.peek()+" ["+j+"/"+links+"]"); 
      //Runnable worker = new CollectorThread(LinksToVisit.poll()); 
      workers[i] = new CollectorThread(LinksToVisit.poll()); 
      executor.execute(workers[i]); 
     } 
     else break; 
    } 
    executor.shutdown(); 
    while (!executor.isTerminated()) {} 

    SortedCharMap.putAll(CharMap); 

    this.time =(System.nanoTime() - startTime)*10E-10; 
} 

class CollectorThread implements Runnable{ 
    private Document html; 
    private String url; 

    public CollectorThread(String url){ 
     this.url = url; 
     try { 
      this.html = Jsoup.connect(url).get(); 
     } catch (IOException e) { 
      e.printStackTrace(); 
     } 
    } 
    @Override 
    public void run() { 
     if(cvlinks != links){ 
      Elements collectedLinks = html.select("a[href]"); 
      for(Element link:collectedLinks){ 
       if(cvlinks == links) break; 
       else{ 
        String current = link.attr("abs:href"); 
        if(!current.equals(url) && current.startsWith(baseurl)&& !current.contains("#")){ 
         LinksToVisit.add(current); 
         cvlinks++; 
        } 
       } 
      } 
     } 

     AnalyzeDocument(html, url); 
    } 
} 

}

答えて

1

LinksToVisitキューを使用する代わりに、CollectorThread.run()から直接executor.execute(new CollectorThread(current))を呼び出してください。 ExecutorServiceには、スレッドが利用可能になると実行される独自の内部キューがあります。

もう1つの問題は、最初のURLセットをキューに追加した後にshutdown()を呼び出すと、新しいタスクがエグゼキュータに追加されなくなります。キューを空にしたときにエグゼキュータをシャットダウンする代わりに、これを修正できます。

class Queue extends ThreadPoolExecutor { 
    Queue(int nThreads) { 
     super(nThreads, nThreads, 0L, TimeUnit.MILLISECONDS, 
       new LinkedBlockingQueue<Runnable>()); 
    } 

    protected void afterExecute(Runnable r, Throwable t) { 
     if(getQueue().isEmpty()) { 
      shutdown(); 
     } 
    } 
} 
+0

お返事ありがとうございます。 CollectorThread.run()内でexecutor.execute(new CollectorThread(current))を呼び出すことを完全に理解しているかどうかはわかりません。私は労働者を作成するためのループを削除する必要がありますか?何とか再帰的なように機能しますか?ありがとう – eXPi

関連する問題