2012-02-25 105 views
1

我的多線程經驗有限,所以說實話這可能是一個可怕的想法。這是我想做的事:多線程通過正確的列表

的50個URL(例如) 使用X線(例如5)的量清單 調用泛型方法來處理URL中獲得一系列的URL的ArrayList(檢索HTML) 將結果與其他線程結果一起存儲在主列表中

現在我一直在處理ArrayList和多個線程,我當前的想法是按列表中有多少個URL來劃分列表,並分配一個數字範圍到每個線程來處理例如

線程1 - 0-7 線程2 - 8-15

我假設這是一個可怕的方法,但我真的不能找到一個例子方法。

幫助/忠告非常感謝。

+0

同時下載多個HTML頁面是它的最終目標 – Ash 2012-02-25 18:41:39

+0

下載[Java的並發動畫(http://sourceforge.net/projects/javaconcurrenta/),應該給你知道如何解決問題。 – 2012-02-25 19:24:14

回答

4
  1. 創建一個線程池,其中每個線程從列表中每次處理一個網址 。
  2. 保留一個全局索引計數器,以便 線程完成時,它可以從列表中檢索要處理的下一個URL。
  3. 執行此操作,直到處理完所有URL爲止。 index == list.size()

這樣所有的線程都被完全利用,直到作業完成。您可以利用池中的線程數量來優化特定運行時環境的性能。

只要確保您的索引計數器代碼是線程安全的。 :)

+1

使用一個鎖存器而不是一個計數器,主線程可以等待鎖存器... – Nim 2012-02-25 18:41:06

+0

並確保您不要在列表本身和線程在同一時間修改。使用同步功能或現有的併發數據結構等。 – EdH 2012-02-25 18:45:45

1

我接受的替代品/批評......我不是多線程的專家,但在過去,我已經做了這樣的事情:

public class MainController { 

    public static void main(String[] args) { 
     ThreadGroup workers = new ThreadGroup("workers"); 
     Iterator<String> urls = getUrlList().iterator(); 
     while(workers.activeCount() < 5 && urls.hasNext()) { 
      UrlProcessor proc = new UrlProcessor(urls.next()); 
      Thread worker = new Thread(workers, proc); 
      worker.start(); 
     } 
    } 

    private static List<String> getUrlList() { 
     return null; //To change body of created methods use File | Settings | File Templates. 
    } 
} 


public class UrlProcessor implements Runnable { 

    private String url; 

    public UrlProcessor(String url) { 
     this.url = url; 
    } 

    public void run() { 
     // process URL 
    } 
} 
2

一個更容易的方法是隻需使用一個ExecutorService處理點播的網址,然後檢索使用Future S中的結果:

class URLProcessor { 

    class ThreadTask implements Callable<String> { 
     private String url; 

     public ThreadTask(String url) { 
      this.url = url; 
     } 

     public String call() { 
      // process url 
      // return a String result 
     } 
    } 

... 


// input urls 
List<String> urls = new ArrayList<String>(); 
// futures to retrieve task results 
List<Future<String>> futures = new ArrayList<Future<String>>(); 
// results 
List<String> results = new ArrayList<String>(); 
// pool with 5 threads 
ExecutorService exec = Executors.newFixedThreadPool(5); 

// enqueue tasks 
for(String url: urls) { 
    futures.add(exec.submit(new ThreadTask(url))); 
} 

// wait for tasks to finish 
for(Future<String> future: futures) { 
    results.add(future.get()); 
} 
+0

感謝您的例子,結束了使用這個,我欠你:) – Ash 2012-02-26 08:26:51

+0

@Ash:你的問題仍然沒有解決?你有沒有發現這種方法的其他問題? – Tudor 2012-02-26 15:03:49

1

每個URL創建任務,並提交給一個Executor。

任務看起來是這樣的:

class UrlTask implements Callable<String>{ 
    final URL url; 

    UrlTask(URL url){ 
     this.url = url; 
    } 

    public String call(){ 
     return fetch(url); 
    } 
} 

像這樣使用:

Collection<Future<String>> results = new Arraylist<Future<String>>(); 
for(URL each : urls){ 
    UrlTask task = new UrlTask(each); 
    Future<String> result = executor.submit(task); 
    results.add(result); 
} 

for(Future<String> result : results){ 
    String content = result.get(); 
    // process content 
} 
1

線程池提供了一個解決方案,既開銷線程生命週期的問題和問題的資源顛簸。

你可能想在這裏尋找Thread pools and work queues