您的位置:首页 > 理论基础 > 计算机网络

HttpUrlConnection与HttpClient的认识(七) -HttpClient的线程安全问题

2017-06-20 11:32 357 查看
转载自:http://blog.csdn.net/u010248330/article/details/69524542

对于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();
}

}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32

开启多线程使用一下这个类:
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);
}

});
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

我们可以访问一下是完全没有问题的。

实际在我们的项目中,会经常将HttpClient封装成单例的形式,因为我们在多处需要进行HTTP通信发送网络请求时,没必要为每个请求都创建一个新的HttpClient,一个HttpCli
1ddc4
ent就可以了。 

但是在多线程情况下访问是出问题的,那我们看看这种情况:

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();
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40

在测试的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(BufferedInputStream.java:218)
at java.io.BufferedInputStream.read(BufferedInputStream.java:237)
at org.apache.commons.httpclient.HttpParser.readRawLine(HttpParser.java:78)
at org.apache.commons.httpclient.HttpParser.readLine(HttpParser.java:106)
at org.apache.commons.httpclient.HttpConnection.readLine(HttpConnection.java:1116)
at org.apache.commons.httpclient.HttpMethodBase.readStatusLine(HttpMethodBase.java:1973)
at org.apache.commons.httpclient.HttpMethodBase.readResponse(HttpMethodBase.java:1735)
at org.apache.commons.httpclient.HttpMethodBase.execute(HttpMethodBase.java:1098)
at org.apache.commons.httpclient.HttpMethodDirector.executeWithRetry(HttpMethodDirector.java:398)
at org.apache.commons.httpclient.HttpMethodDirector.executeMethod(HttpMethodDirector.java:171)
at org.apache.commons.httpclient.HttpClient.executeMethod(HttpClient.java:397)
at org.apache.commons.httpclient.HttpClient.executeMethod(HttpClient.java:323)
at com.httpClient.thread.test.HttpClientUtil2.httpClientGet(HttpClientUtil2.java:24)
at com.httpClient.thread.test.TestHttpClientThreadPro$1.run(TestHttpClientThreadPro.java:18)
at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:895)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:918)
at java.lang.Thread.run(Thread.java:662)
org.apache.commons.httpclient.ProtocolException: Unable to parse header: e8anpt
at org.apache.commons.httpclient.HttpParser.parseHeaders(HttpParser.java:202)
at org.apache.commons.httpclient.HttpMethodBase.readResponseHeaders(HttpMethodBase.java:1935)
at org.apache.commons.httpclient.HttpMethodBase.readResponse(HttpMethodBase.java:1737)
at org.apache.commons.httpclient.HttpMethodBase.execute(HttpMethodBase.java:1098)
at org.apache.commons.httpclient.HttpMethodDirector.executeWithRetry(HttpMethodDirector.java:398)
at org.apache.commons.httpclient.HttpMethodDirector.executeMethod(HttpMethodDirector.java:171)
at org.apache.commons.httpclient.HttpClient.executeMethod(HttpClient.java:397)
at org.apache.commons.httpclient.HttpClient.executeMethod(HttpClient.java:323)
at com.httpClient.thread.test.HttpClientUtil2.httpClientGet(HttpClientUtil2.java:24)
at com.httpClient.thread.test.TestHttpClientThreadPro$1.run(TestHttpClientThreadPro.java:18)
at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:895)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:918)
at java.lang.Thread.run(Thread.java:662)
java.io.IOException: Stream closed
at java.io.BufferedInputStream.getBufIfOpen(BufferedInputStream.java:145)
at java.io.BufferedInputStream.fill(BufferedInputStream.java:189)
at java.io.BufferedInputStream.read(BufferedInputStream.java:237)
at org.apache.commons.httpclient.HttpParser.readRawLine(HttpParser.java:78)
at org.apache.commons.httpclient.HttpParser.readLine(HttpParser.java:106)
at org.apache.commons.httpclient.HttpConnection.readLine(HttpConnection.java:1116)
at org.apache.commons.httpclient.HttpMethodBase.readStatusLine(HttpMethodBase.java:1973)
at org.apache.commons.httpclient.HttpMethodBase.readResponse(HttpMethodBase.java:1735)
at org.apache.commons.httpclient.HttpMethodBase.execute(HttpMethodBase.java:1098)
at org.apache.commons.httpclient.HttpMethodDirector.executeWithRetry(HttpMethodDirector.java:398)
at org.apache.commons.httpclient.HttpMethodDirector.executeMethod(HttpMethodDirector.java:171)
at org.apache.commons.httpclient.HttpClient.executeMethod(HttpClient.java:397)
at org.apache.commons.httpclient.HttpClient.executeMethod(HttpClient.java:323)
at com.httpClient.thread.test.HttpClientUtil2.httpClientGet(HttpClientUtil2.java:24)
at com.httpClient.thread.test.TestHttpClientThreadPro$1.run(TestHttpClientThreadPro.java:18)
at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:895)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:918)
at java.lang.Thread.run(Thread.java:662)
java.lang.IllegalStateException: Unexpected release of an unknown connection.
at org.apache.commons.httpclient.SimpleHttpConnectionManager.releaseConnection(SimpleHttpConnectionManager.java:225)
at org.apache.commons.httpclient.HttpConnection.releaseConnection(HttpConnection.java:1179)
at org.apache.commons.httpclient.HttpMethodBase.ensureConnectionRelease(HttpMethodBase.java:2430)
at org.apache.commons.httpclient.HttpMethodBase.responseBodyConsumed(HttpMethodBase.java:2422)
at org.apache.commons.httpclient.HttpMethodBase$1.responseConsumed(HttpMethodBase.java:1892)
at org.apache.commons.httpclient.AutoCloseInputStream.notifyWatcher(AutoCloseInputStream.java:198)
at org.apache.commons.httpclient.AutoCloseInputStream.checkClose(AutoCloseInputStream.java:170)
at org.apache.commons.httpclient.AutoCloseInputStream.read(AutoCloseInputStream.java:109)
at sun.nio.cs.StreamDecoder.readBytes(StreamDecoder.java:264)
at sun.nio.cs.StreamDecoder.implRead(StreamDecoder.java:306)
at sun.nio.cs.StreamDecoder.read(StreamDecoder.java:158)
at java.io.InputStreamReader.read(InputStreamReader.java:167)
at java.io.BufferedReader.fill(BufferedReader.java:136)
at java.io.BufferedReader.readLine(BufferedReader.java:299)
at java.io.BufferedReader.readLine(BufferedReader.java:362)
at com.httpClient.thread.test.HttpClientUtil2.httpClientGet(HttpClientUtil2.java:29)
at com.httpClient.thread.test.TestHttpClientThreadPro$1.run(TestHttpClientThreadPro.java:18)
at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:895)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:918)
at java.lang.Thread.run(Thread.java:662)
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.
Exception in thread "pool-1-thread-1" java.lang.IllegalStateException: Unexpected release of an unknown connection.
at org.apache.commons.httpclient.SimpleHttpConnectionManager.releaseConnection(SimpleHttpConnectionManager.java:225)
at org.apache.commons.httpclient.HttpConnection.releaseConnection(HttpConnection.java:1179)
at org.apache.commons.httpclient.HttpMethodBase.ensureConnectionRelease(HttpMethodBase.java:2430)
at org.apache.commons.httpclient.HttpMethodBase.releaseConnection(HttpMethodBase.java:1186)
at com.httpClient.thread.test.HttpClientUtil2.httpClientGet(HttpClientUtil2.java:37)
at com.httpClient.thread.test.TestHttpClientThreadPro$1.run(TestHttpClientThreadPro.java:18)
at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:895)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:918)
at java.lang.Thread.run(Thread.java:662)
java.lang.IllegalStateException: Connection is not open
at org.apache.commons.httpclient.HttpConnection.assertOpen(HttpConnection.java:1277)
at org.apache.commons.httpclient.HttpConnection.readLine(HttpConnection.java:1115)
at org.apache.commons.httpclient.HttpMethodBase.readStatusLine(HttpMethodBase.java:1973)
at org.apache.commons.httpclient.HttpMethodBase.readResponse(HttpMethodBase.java:1735)
at org.apache.commons.httpclient.HttpMethodBase.execute(HttpMethodBase.java:1098)
at org.apache.commons.httpclient.HttpMethodDirector.executeWithRetry(HttpMethodDirector.java:398)
at org.apache.commons.httpclient.HttpMethodDirector.executeMethod(HttpMethodDirector.java:171)
at org.apache.commons.httpclient.HttpClient.executeMethod(HttpClient.java:397)
at org.apache.commons.httpclient.HttpClient.executeMethod(HttpClient.java:323)
at com.httpClient.thread.test.HttpClientUtil2.httpClientGet(HttpClientUtil2.java:24)
at com.httpClient.thread.test.TestHttpClientThreadPro$1.run(TestHttpClientThreadPro.java:18)
at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:895)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:918)
at java.lang.Thread.run(Thread.java:662)
org.apache.commons.httpclient.ProtocolException: Unable to parse header: T 0 K
at org.apache.commons.httpclient.HttpParser.parseHeaders(HttpParser.java:202)
at org.apache.commons.httpclient.HttpMethodBase.readResponseHeaders(HttpMethodBase.java:1935)
at org.apache.commons.httpclient.HttpMethodBase.readResponse(HttpMethodBase.java:1737)
at org.apache.commons.httpclient.HttpMethodBase.execute(HttpMethodBase.java:1098)
at org.apache.commons.httpclient.HttpMethodDirector.executeWithRetry(HttpMethodDirector.java:398)
at org.apache.commons.httpclient.HttpMethodDirector.executeMethod(HttpMethodDirector.java:171)
at org.apache.commons.httpclient.HttpClient.executeMethod(HttpClient.java:397)
at org.apache.commons.httpclient.HttpClient.executeMethod(HttpClient.java:323)
at com.httpClient.thread.test.HttpClientUtil2.httpClientGet(HttpClientUtil2.java:24)
at com.httpClient.thread.test.TestHttpClientThreadPro$1.run(TestHttpClientThreadPro.java:18)
at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:895)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:918)
at java.lang.Thread.run(Thread.java:662)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121

我们发现代码报错了,说明这是线程不安全的一种封装。。

针对这种情况,HttpClient提供了MultiThreadedHttpConnectionManager解决这种线程不安全的请求。使用起来很简单:
MultiThreadedHttpConnectionManager connectionManager =
new MultiThreadedHttpConnectionManager();
HttpClient httpClient= new HttpClient(connectionManager);
1
2
3
1
2
3

这样封装的httpClient使用起来就没问题了。

3.MultiThreadedHttpConnectionManager解决线程安全的问题
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.MultiThreadedHttpConnectionManager;
import org.apache.commons.httpclient.methods.GetMethod;
import org.apache.commons.httpclient.params.HttpConnectionManagerParams;
import org.apache.commons.httpclient.params.HttpMethodParams;
/**
* 线程安全的封装
*/
public class HttpClientUtil3 {

private static MultiThreadedHttpConnectionManager connectionManager;
private static HttpClient httpClient;
private static int maxHostConnections = 10;
private static int maxTotalConnections = 20;
static {
connectionManager = new MultiThreadedHttpConnectionManager();
HttpConnectionManagerParams params = new HttpConnectionManagerParams();
params.setDefaultMaxConnectionsPerHost(maxHostConnections);
params.setMaxTotalConnections(maxTotalConnections);
connectionManager.setParams(params);
httpClient = new HttpClient(connectionManager);
httpClient.getParams().setParameter(HttpMethodParams.HTTP_CONTENT_CHARSET, "UTF-8");
}
public static String httpClientGet(String url){

StringBuilder sb =new StringBuilder();
GetMethod getMethod = new GetMethod(url);
try {
//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();
}

}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53

在测试的TestHttpClientThreadPro类中修改为
HttpClientUtil3.httpClientGet(url);


运行代码没有任何问题。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: