2012-02-25 31 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