使用java的HttpClient实现多线程并发

 更新时间:2016年09月11日 15:23:08   投稿:hebedich  
这篇文章主要介绍了使用java的HttpClient实现多线程并发的相关资料,需要的朋友可以参考下

说明:以下的代码基于httpclient4.5.2实现。

我们要使用java的HttpClient实现get请求抓取网页是一件比较容易实现的工作:

  public static String get(String url) {
    CloseableHttpResponseresponse = null;
    BufferedReader in = null;
    String result = "";
    try {
      CloseableHttpClienthttpclient = HttpClients.createDefault();
      HttpGethttpGet = new HttpGet(url);
      response = httpclient.execute(httpGet);
 
      in = new BufferedReader(new InputStreamReader(response.getEntity().getContent()));
      StringBuffersb = new StringBuffer("");
      String line = "";
      String NL = System.getProperty("line.separator");
      while ((line = in.readLine()) != null) {
        sb.append(line + NL);
      }
      in.close();
      result = sb.toString();
    } catch (IOException e) {
      e.printStackTrace();
    } finally {
      try {
        if (null != response) response.close();
      } catch (IOException e) {
        e.printStackTrace();
      }
    }
    return result;
  }

要多线程执行get请求时上面的方法也堪用。不过这种多线程请求是基于在每次调用get方法时创建一个HttpClient实例实现的。每个HttpClient实例使用一次即被回收。这显然不是一种最优的实现。

HttpClient提供了多线程请求方案,可以查看官方文档的《 Pooling connection manager 》这一节。HttpCLient实现多线程请求是基于内置的连接池实现的,其中有一个关键的类即PoolingHttpClientConnectionManager,这个类负责管理HttpClient连接池。在PoolingHttpClientConnectionManager中提供了两个关键的方法:setMaxTotal和setDefaultMaxPerRoute。setMaxTotal设置连接池的最大连接数,setDefaultMaxPerRoute设置每个路由上的默认连接个数。此外还有一个方法setMaxPerRoute——单独为某个站点设置最大连接个数,像这样:

   HttpHosthost = new HttpHost("locahost", 80);
   cm.setMaxPerRoute(new HttpRoute(host), 50);

根据文档稍稍调整下我们的get请求实现:

package com.zhyea.robin;
 
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
 
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
 
public class HttpUtil {
 
  private static CloseableHttpClienthttpClient;
 
  static {
    PoolingHttpClientConnectionManagercm = new PoolingHttpClientConnectionManager();
    cm.setMaxTotal(200);
    cm.setDefaultMaxPerRoute(20);
    cm.setDefaultMaxPerRoute(50);
    httpClient = HttpClients.custom().setConnectionManager(cm).build();
  }
 
  public static String get(String url) {
    CloseableHttpResponseresponse = null;
    BufferedReaderin = null;
    String result = "";
    try {
 
      HttpGethttpGet = new HttpGet(url);
      response = httpClient.execute(httpGet);
 
      in = new BufferedReader(new InputStreamReader(response.getEntity().getContent()));
      StringBuffersb = new StringBuffer("");
      String line = "";
      String NL = System.getProperty("line.separator");
      while ((line = in.readLine()) != null) {
        sb.append(line + NL);
      }
      in.close();
      result = sb.toString();
    } catch (IOException e) {
      e.printStackTrace();
    } finally {
      try {
        if (null != response) response.close();
      } catch (IOException e) {
        e.printStackTrace();
      }
    }
    return result;
  }
 
  public static void main(String[] args) {
    System.out.println(get("https://www.baidu.com/"));
  }
}

这样就差不多了。不过对于我自己而言,我更喜欢httpclient的fluent实现,比如我们刚才实现的http get请求完全可以这样简单的实现:

package com.zhyea.robin;
 
import org.apache.http.client.fluent.Request;
import java.io.IOException;
 
public class HttpUtil {
 
  public static String get(String url) {
    String result = "";
    try {
      result = Request.Get(url)
          .connectTimeout(1000)
          .socketTimeout(1000)
          .execute().returnContent().asString();
    } catch (IOException e) {
      e.printStackTrace();
    }
    return result;
  }
 
  public static void main(String[] args) {
    System.out.println(get("https://www.baidu.com/"));
  }
}

我们要做的只是将以前的httpclient依赖替换为fluent-hc依赖:

<dependency>
   <groupId>org.apache.httpcomponents</groupId>
   <artifactId>fluent-hc</artifactId>
   <version>4.5.2</version>
</dependency>

并且这个fluent实现天然就是采用PoolingHttpClientConnectionManager完成的。它设置的maxTotal和defaultMaxPerRoute的值分别是200和100:

    CONNMGR = new PoolingHttpClientConnectionManager(sfr);
    CONNMGR.setDefaultMaxPerRoute(100);
    CONNMGR.setMaxTotal(200);

唯一一点让人不爽的就是Executor没有提供调整这两个值的方法。不过这也完全够用了,实在不行的话,还可以考虑重写Executor方法,然后直接使用Executor执行get请求:

Executor.newInstance().execute(Request.Get(url))
        .returnContent().asString();

就这样!

相关文章

  • resty upload无需依赖的文件上传与下载

    resty upload无需依赖的文件上传与下载

    这篇文章主要为大家介绍了resty upload中无需依赖的文件上传与下载过程,有需要的朋友可以借鉴参考下,希望能够有所帮助祝大家多多进步,早日升职加薪
    2022-03-03
  • Java IO之字节输入输出流详解

    Java IO之字节输入输出流详解

    这篇文章主要为大家介绍了Java IO之字节输入输出流,具有一定的参考价值,感兴趣的小伙伴们可以参考一下,希望能够给你带来帮助
    2022-01-01
  • 解决使用@ResponseBody后返回500错误的问题

    解决使用@ResponseBody后返回500错误的问题

    这篇文章主要介绍了解决使用@ResponseBody后返回500错误的问题,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2020-09-09
  • Java BeanDefination接口详细讲解

    Java BeanDefination接口详细讲解

    BeanDefinition是spring里面bean的一个建模对象,就相当于class对象是普通java对象的建模对象一样。可能在spring作用的各种业务场景中,class对象并不能完成spring对bean的抽象,所以弄了一个BeanDefinition作为bean的抽象建模对象
    2022-11-11
  • Java Swing实现简单的体重指数(BMI)计算器功能示例

    Java Swing实现简单的体重指数(BMI)计算器功能示例

    这篇文章主要介绍了Java Swing实现简单的体重指数(BMI)计算器功能,涉及Java Swing窗口组件布局、响应及数值运算相关操作技巧,需要的朋友可以参考下
    2017-12-12
  • Java优化for循环嵌套的高效率方法

    Java优化for循环嵌套的高效率方法

    这篇文章主要介绍了Java优化for循环嵌套的高效率方法,帮助大家更好的提升java程序性能,感兴趣的朋友可以了解下
    2020-09-09
  • 浅谈一下Java中枚举的用法

    浅谈一下Java中枚举的用法

    这篇文章主要介绍了浅谈一下Java中枚举的用法,枚举是一个被命名的整型常数的集合,用于声明一组带标识符的常数,当一个变量有几种固定可能的取值时,就可以将它定义为枚举类型,需要的朋友可以参考下
    2023-04-04
  • Java中的阻塞队列BlockingQueue使用详解

    Java中的阻塞队列BlockingQueue使用详解

    这篇文章主要介绍了Java中的阻塞队列BlockingQueue使用详解,阻塞队列是一种线程安全的数据结构,用于在多线程环境下进行数据交换,它提供了一种阻塞的机制,当队列为空时,消费者线程将被阻塞,直到队列中有数据可供消费,需要的朋友可以参考下
    2023-10-10
  • java实现http请求工具类示例

    java实现http请求工具类示例

    这篇文章主要介绍了java实现http请求工具类示例,需要的朋友可以参考下
    2014-05-05
  • Java forEach对原数组的操作过程

    Java forEach对原数组的操作过程

    forEach对于基本数据类型,是直接赋值,对于引用数据类型,是引用地址值,forEach遍历时,是创建的临时变量,引用的数据地址,本文给大家介绍Java forEach对原数组的操作过程,感兴趣的朋友一起看看吧
    2024-02-02

最新评论