使用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();
就这样!


猜你喜欢
- android获取ibeacon列表,供大家参考,具体内容如下最近公司有需要做ibeacon需求。因为涉及扫码的时间。特意写一个servic
- 本文实例为大家分享了Android DialogUtils弹出窗工具类的具体代码,供大家参考,具体内容如下直接上代码吧!!!代码拉过去都可以
- 演示代码: MenuExamples.java package swt_jface.demo5; import org.eclipse.sw
- jax-ws handler 的详解及简单实例aop技术一般用于某个对象的函数调用的日志,认证等。webservice是远程的函
- 发现问题最近工作中利用JNA 调用 dll 库时保错,错误如下:///////////////// 通过 JNA 引入 DLL 库 ////
- 背景介绍1,最近有一个大数据量插入的操作入库的业务场景,需要先做一些其他修改操作,然后在执行插入操作,由于插入数据可能会很多,用到多线程去拆
- 由于最近项目更新功能比较的忙,也没时间去整理自己的知识点和管理自己的博客.在Android对手机相册中的图片的压缩和上传到服务器上,这样的功
- 在项目中有使用到延时队列的场景,做个简单的记录说明;首先DelayQueue实现了BlockingQueue,加入其中的元素必须实现Dela
- 1.MyBatis简介MyBatis 是一款优秀的持久层框架,它支持定制化 SQL、存储过程以及高级映射。MyBatis 避免了几乎所有的
- C语言实现矩阵运算给定一个n×n的方阵,本题要求计算该矩阵除副对角线、最后一列和最后一行以外的所有元素之和。副对角线为从矩阵的右上角至左下角
- Spring Boot怎么实现热部署在Spring Boot实现代码热部署是一件很简单的事情,代码的修改可以自动部署并重新热启动项目。1、引
- Java * 模式 代理:一个角色代表别一个角色来实现某些特定的能功。 比
- 使用INI配置文件,简单便捷。该辅助工具类为C#操作INI文件的辅助类,源码在某位师傅的基础上完善的来,因为忘记最初的来源了,因此不能提及引
- 主要思想:将一个view设计成多层:背景层,含中奖信息等;遮盖层,用于刮奖,使用关联一个Bitmap的Canvas在该Bitmap上,使用它
- 实践过程效果代码public partial class frmSend : Form{ public frmSe
- 详解java中的PropertyChangeSupport与PropertyChangeListenerjava中的PropertyChan
- 本文实例为大家分享了Unity2D游戏回旋镖实现的具体代码,供大家参考,具体内容如下以下我举出2种同使用情况的回旋镖那么回旋镖需要怎么做呢?
- 首先客户端从服务器端获取json数据1、利用HttpUrlConnection/** &nbs
- 为什么是MVI而不是MVVMMVVM作为流行的架构模式,应用在 Compose上,并没有大的问题或者设计缺陷。但是在使用期间,发现了并不适合
- 1 前言在项目开发中,异步化处理是非常常见的解决问题的手段,异步化处理除了使用线程池之外,还可以使用 CompletableFut