使用多线程在java中下载

时间:2015-09-12 16:13:30

标签: java multithreading concurrency java-threads

我正在尝试同时下载其网址存储在数据库中的网站的HTML代码(大约3百万条目)。
很明显我应该使用多线程技术但是我在java中如何做到这一点很麻烦。

这是我以前没有多线程的方式:

final Connection c = dbConnect(); // register jdbc-driver and establish connection
checkRequiredDbAndTables();  // here we check the existence of the Db and necessary tables

try {
    // now get list of urls from the db
    String sql = "select id, website_url, category_id from list_of_websites";
    PreparedStatement ps = c.prepareStatement(sql);
    ResultSet rs = ps.executeQuery();

    while (rs.next()) {
    // column numeration in ResultSet is from 1 !
        final long id = rs.getInt(1);   // get website id
        final String url = rs.getString(2);   // get website url

        System.out.println("Category: " + rs.getString(3) + " " + id + " " + url);

        if ( isValidURL(url) && connectionOK(url) ) {
        // checked url syntax and connection 
            String htmlInPage = downloadHTML(url);
            if (!htmlInPage.equals("")) {
            // add result to db
                insertDataToDb( c, id, htmlInPage);
             }
        }
    }
    rs.close();
 } catch (SQLException e) {
        e.printStackTrace();
 }
    closeConnection(c);  // database connection closed

函数donloadHTML使用JSoup库来完成主要工作。

感觉我的任务是一种“生产者消费者问题”。我想它可以用这样的方式表示:有一个缓冲区,包含N个链接;一些进程从它获取链接和下载HTML;和一个进程,其目的是将db中的新URL加载到缓冲区中,因为它变为空。
但我完全不知道该怎么做。我听说ThreadsExecutorService提供了ThreadPools,但它对我来说真的很混乱。

2 个答案:

答案 0 :(得分:2)

您可能想要使用Thread pool that has fixed amount of thread。您的计划将首先create a thread pool。然后它将从数据库中读取URL。读取URL后,程序将start a new task下载其内容。

您的程序可能会保留queue。当任务完成下载HTML时,它可以将URL和结果一起推送到队列中。当主线程完成读取URL和启动任务时,它可以等待队列。 Once the queue have any responsestake the response out并将其写入数据库。主线程可以计算接收到的响应数量,当计入URL数量时,所有任务都完成。

您的程序可以编写一个类来存储带有URL的响应,例如:

class response {
    public String URL;
    public String result;
    public response(String u, String r) { this.URL = u; this.result = r; }
}

如果你仍然有任何实施或理解方面的问题(我可能不会解释清楚,现在是00:40,我很快就会入睡。),请留下评论。如果您需要代码,请同时留下评论。

答案 1 :(得分:0)

主线程:

  • 启动X“下载”主题
  • 运行有问题的查询。 for每条记录:
    • 将查询中的数据添加到ArrayBlockingQueue
  • 将数据结束标记添加到队列
  • 等待线程停止(可选)
  • main
  • 返回

下载主题:

  • 从队列中获取数据。 while不是数据结束标记:
    • 下载HTML
    • 将HTML插入数据库
  • 将数据结束标记放回队列以供其他线程查找
  • 退出主题