【问题标题】:use of multithreading for downloading in java在java中使用多线程进行下载
【发布时间】:2015-09-12 16:13:29
【问题描述】:

我正在尝试同时下载其网址存储在数据库中的网站的 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,但这对我来说真的很困惑。

【问题讨论】:

  • 为什么很明显你应该对 IO 绑定的东西使用多线程?
  • 1.您提供的代码与问题完全无关。 2. 代码使用我们无法发表意见的方法
  • 您已经“听说”过 Threads 并且它们让您感到困惑?您是否尝试过阅读以了解更多信息?例如这里:docs.oracle.com/javase/tutorial/essential/concurrency/…
  • @Jeff 能够从 fastwebsite.com 下载 200 个页面,而另一个线程被阻止等待 slowwebsite.com 响应。
  • @JacekCz ,1)我提供了我现在拥有的代码,并希望以多线程方式更改它,但不知道如何 2)假设此方法正常工作。 protected Connection dbConnect() { String url = host + db; Class.forName(driver); // Register JDBC driver Connection c = DriverManager.getConnection(url, user, password); // Open a connection return c; }当然要处理异常

标签: java multithreading concurrency java-threads


【解决方案1】:

您可能想使用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 responses, take 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,我可能很快就会去睡觉。),请离开 cmets。如果要代码,也请留下cmets。

【讨论】:

  • 感谢您的创意!我现在有一些工作变体...pastebin.com/aC7kURMA 好吗?事实上,它只需要对我的原始代码进行最小的更改,只需用 Runnable 包装它。队列的解决方案看起来不错,但我已经有 1 个数据结构:ResultSet - 并且害怕创建另一个,尤其是它会有很多数据
  • @Tofrar 您可能不需要只有 8 个线程。这取决于您的网络速度。如果网站不限制最大并行连接数,你可以有 20 个线程。
  • 我增加了多达 20 个线程,一切正常。而且非常快)我会尝试尝试并找到最佳数字)谢谢!)
【解决方案2】:

主线程:

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

下载线程:

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-11-20
    • 1970-01-01
    相关资源
    最近更新 更多