使用java的HttpClient实现多线程并发
作者:hebedich 发布时间:2022-09-19 20:35:55
说明:以下的代码基于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();
就这样!
猜你喜欢
- 基本概念Spring Validation 验证框架对参数的验证机制提供了@Validated(Spring's JSR-303规范
- 目录为什么选择MQTTMQTT, 启动!使用方式Client模式创建工厂类创建工具类Spring Integration总结为什么选择MQT
- 前言Android暂时还没有提供一个合适的API来获取/监听键盘的状态和高度 , 而我们又经常会有这个需求.最近我的一个项目中,在ugc页面
- 前言前一篇文章我们熟悉了HikariCP连接池,也了解到它的性能很高,今天我们讲一下另一款比较受欢迎的连接池:Druid,这是阿里开源的一款
- 所以对于应用层用着还不是很方便。最近做一个项目顺便就封装了一个调用默认打印机的类。虽说有几个小bug,但对于目前来说,已经满足需求了。以后不
- 注:如果没有 root 权限也是可以试试,一般情况下,都需要 root 权限,才能连接成功。1.需要确保你的开发 PC 和 Android
- 记录自己用java swing做的第一个简易界面。LoginAction.javapackage com.QQUI0819;import j
- 前言在java Thread类中,我们会看到interrupt()、interrupted()及isInterrupted(),在大多数情况
- 1、CyclicBarrier:一个同步辅助类,用于协调多个子线程,让多个子线程在这个屏障前等待,直到所有子线程都到达了这个屏障时,再一起继
- java中的final关键字详解final的作用随着所修饰的类型而不同  
- 一、概述无论是什么语言,在多线程编程中,常常会遇到多个线同时操作程某个变量(读/写),如果读/写不同步,则会造成不符合预期的结果。例如:线程
- 首先感谢:http://www.codeproject.com/Articles/25487/Cryptographic-Interoper
- 本文实例为大家分享了Android九宫格图片展示的具体代码,供大家参考,具体内容如下1.RandomAccessFileRandomAcce
- 笔者在使用Entity Framework中的Scaffolding机制自动创建拓展名为mdf的数据库及表单时,遇到如下的错误:A file
- 本文实例讲述了C#实现把图片转换成二进制以及把二进制转换成图片的方法。分享给大家供大家参考,具体如下:private void button
- Java 字符串反转问题:给一个字符串,比如 “I love china”, 把字符反转后变成 “china love I”思路
- 想问下这是什么情况。在导入一个maven项目时只有一个finish,点击完finish后没有任何反应。。。各位大佬给看下这是什么问题。急,在
- 第1部分 HashMap介绍HashMap简介HashMap 是一个散列表,它存储的内容是键值对(key-value)映射。HashMap
- 引言:最近在工作中遇到与某些API对接的post的数据需要将对象的字段首字母小写。解决办法有两种:第一种:使用对象的字段属性设置JsonPr
- 本文实例讲述了Android动画之补间动画。分享给大家供大家参考,具体如下:前面讲了《Android动画之逐帧动画(Frame Animat