1

我正在尝试同时下载其网址存储在数据库中的网站的 HTML 代码(大约 300 万个条目)。
很明显,我应该使用多线程技术,但我遇到了如何在 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;和一个过程,其目的是在缓冲区变空时将新的 url 从 db 加载到缓冲区中。
但我完全不知道该怎么做。我听说过ThreadsExecutorService提供过,ThreadPools但这对我来说真的很困惑。

4

2 回答 2

2

您可能想要使用具有固定数量线程的线程池。您的程序将首先创建一个线程池。然后它将从数据库中读取 URL。读取 URL 时,程序将启动一个新任务来下载其内容。

您的程序可能会维护一个队列。当任务完成下载 HTML 时,它可以将 URL 和结果一起推送到队列中。当主线程完成读取 URL 并启动任务后,就可以等待队列了。一旦队列有任何响应将响应取出并将其写入数据库。主线程可以统计收到了多少响应,当它统计到 URL 的数量时,则所有任务都完成了。

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

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

如果您在实施或理解方面仍有任何问题(我可能解释得不够清楚,现在是 00:40,我可能很快就会睡觉。),请发表评论。如果你想要代码,也请留下评论。

于 2015-09-12T16:40:04.817 回答
0

主线程:

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

下载线程:

  • 从队列中获取数据。while不是数据结束标记:
    • 下载 HTML
    • 将 HTML 插入数据库
  • 将数据结束标记放回队列中以供其他线程查找
  • 退出线程
于 2015-09-12T16:41:07.363 回答