对于HttpClient的使用,我们在项目中一般会封装成一个工具栏使用,方便调用,在 HttpUrlConnection与HttpClient的认识(四) -HttpClient的封装 这篇博客中,已经说明过了。
上次的封装是没有问题的,我们拿来测试一下。
1、线程安全的封装
package com.httpClient.thread.test;
import org.apache.commons.httpclient.*;
import org.apache.commons.httpclient.methods.*;
import java.io.*;
/**
*线程安全的封装,因为每次都是重新实例化的HttpClient
*/
public class HttpClientUtil1 {
public static String httpClientGet(String url){
StringBuilder sb =new StringBuilder();
//每次都重新实例化一个httpClient
HttpClient httpClient = new HttpClient();
GetMethod getMethod = new GetMethod(url);
try {
httpClient.executeMethod(getMethod);
InputStream is = getMethod.getResponseBodyAsStream();
BufferedReader dis=new BufferedReader(new InputStreamReader(is,"utf-8"));
String str ="";
while((str =dis.readLine())!=null){
sb.append(str);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
// 关闭连接
getMethod.releaseConnection();
}
return sb.toString();
}
}
开启多线程使用一下这个类:
package com.httpClient.thread.test;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class TestHttpClientThreadPro {
private static String url="http://www.baidu.com";
public static void main(String[] args) {
ExecutorService threadPool=Executors.newFixedThreadPool(4);
for ( int i = 0; i < 6; i++) {
threadPool.execute(new Runnable() {
@Override
public void run() {
HttpClientUtil1.httpClientGet(url);
System.out.println("=====访问结果==="+result);
}
});
}
}
}
我们可以访问一下是完全没有问题的。
实际在我们的项目中,会经常将HttpClient封装成单例的形式,因为我们在多处需要进行HTTP通信发送网络请求时,没必要为每个请求都创建一个新的HttpClient,一个HttpClient就可以了。
但是在多线程情况下访问是出问题的,那我们看看这种情况:
2.线程不安全的封装
package com.httpClient.thread.test;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.methods.GetMethod;
import org.apache.commons.httpclient.params.HttpMethodParams;
/**
*线程不安全,只有唯一的一个实例
*/
public class HttpClientUtil2 {
//唯一的HttpClient实例
private static HttpClient httpClient=new HttpClient();
public static String httpClientGet(String url){
StringBuilder sb =new StringBuilder();
GetMethod getMethod = new GetMethod(url);
try {
httpClient.getParams().setParameter(HttpMethodParams.HTTP_CONTENT_CHARSET, "utf-8");
httpClient.getHttpConnectionManager().getParams().setConnectionTimeout(3000);
httpClient.getHttpConnectionManager().getParams().setSoTimeout(3000);
//httpClient永远是同一个
int statusCode = httpClient.executeMethod(getMethod);
if (statusCode==200) {
InputStream is = getMethod.getResponseBodyAsStream();
BufferedReader dis=new BufferedReader(new InputStreamReader(is,"utf-8"));
String str ="";
while((str =dis.readLine())!=null){
sb.append(str);
sb.append("\r\n");
}
}
} catch (Exception e) {
e.printStackTrace();
}finally{
getMethod.releaseConnection();
}
return sb.toString();
}
}
在测试的TestHttpClientThreadPro类中修改为
HttpClientUtil2.httpClientGet(url);
运行代码:
2017-4-7 10:48:25 org.apache.commons.httpclient.SimpleHttpConnectionManager getConnectionWithTimeout
警告: SimpleHttpConnectionManager being used incorrectly. Be sure that HttpMethod.releaseConnection() is always called and that only one thread and/or method is using this connection manager at a time.
2017-4-7 10:48:25 org.apache.commons.httpclient.SimpleHttpConnectionManager getConnectionWithTimeout
警告: SimpleHttpConnectionManager being used incorrectly. Be sure that HttpMethod.releaseConnection() is always called and that only one thread and/or method is using this connection manager at a time.
2017-4-7 10:48:25 org.apache.commons.httpclient.SimpleHttpConnectionManager getConnectionWithTimeout
警告: SimpleHttpConnectionManager being used incorrectly. Be sure that HttpMethod.releaseConnection() is always called and that only one thread and/or method is using this connection manager at a time.
java.net.SocketException: Socket Closed
at java.net.SocketInputStream.socketRead0(Native Method)
at java.net.SocketInputStream.read(SocketInputStream.java:129)
at java.io.BufferedInputStream.fill