本身封装了一个请求类,因为本身写的时候太自觉得是,致使多线程请求的时候报错 java
18:33 INFO [o.a.h.i.e.RetryExec] I/O exception (java.net.SocketException) caught when processing request to {}->http://172.10.10.xxx:xxxx: Socket Closed web
18:33 INFO [o.a.h.i.e.RetryExec] Retrying request to {}->http://172.10.10.xxx:xxxx spring
还有这样的错误 安全
18:33 ERROR [c.w.p.e.ExceptionMapper] ERROR:500,[PLATFORM]Connection is not open 多线程
18:33 ERROR [c.w.p.e.ExceptionMapper] java.lang.IllegalStateException: Connection is not open 并发
private static PoolingHttpClientConnectionManager cm; private static CloseableHttpClient httpClient = null; private static HttpGet get = null; static { initManager(); } private static void initManager() { cm = new PoolingHttpClientConnectionManager(); cm.setMaxTotal(100); cm.setDefaultMaxPerRoute(2); HttpHost localhost = new HttpHost(PropertyUtil.getProperty("recommend.host"), PropertyUtil.getInteger("recommend.port")); cm.setMaxPerRoute(new HttpRoute(localhost), 100); httpClient = HttpClients.custom().setConnectionManager(cm).build(); get = new HttpGet(); RequestConfig requestConfig = RequestConfig.custom() .setSocketTimeout(1000) .setConnectTimeout(1000) .build(); get.setConfig(requestConfig); } public static String getRecommend(URI uri) { if (httpClient != null && get != null) { try { get.setURI(uri); //注意这里 CloseableHttpResponse response = httpClient.execute(get); get.releaseConnection(); return EntityUtils.toString(response.getEntity(), "utf-8"); } catch (IOException e) { throw new IllegalRequestException(ErrorMessageUtil.RECOMMEND_TIMEOUT); } } else { System.out.println("Error httpClient or get is null!"); } return ""; }
这是最开始的写法,在项目中保证httpclient和get都只生成一个实例,由于是多线程请求,正在作优化,对返回效率敏感,想到建立对象时损耗比较大就使用这种方式,后来就报了上面的2种错误 app
首先要说这个错误的引发是因为多线程的关系,因为我以前写过一个多线程请求的方法,因此我认为在web项目中也能够这样调用 优化
当我解决了这个问题再回去看那个代码的时候我才发现,为何那个没问题,由于在以前的代码里,我指定了一个类继承自Thread,在这个thread里我new了一个HttpGet,因此在这个线程里保证了get只有一个,而在web项目中,spring初始化的时候就new出了一个HttpGet,并且是多线程复用的,这时候就出现了问题 ui
解决方法也很简单: spa
private static PoolingHttpClientConnectionManager cm; private static CloseableHttpClient httpClient = null; private static RequestConfig requestConfig = null; static { initManager(); } private static void initManager() { cm = new PoolingHttpClientConnectionManager(); cm.setMaxTotal(100); cm.setDefaultMaxPerRoute(2); HttpHost localhost = new HttpHost(PropertyUtil.getProperty("recommend.host"), PropertyUtil.getInteger("recommend.port")); cm.setMaxPerRoute(new HttpRoute(localhost), 100); httpClient = HttpClients.custom().setConnectionManager(cm).build(); requestConfig = RequestConfig.custom().setSocketTimeout(1000).setConnectTimeout(1000).build(); } public static String getRecommend(URI uri) { try { HttpGet get = new HttpGet(); //就改这里 get.setConfig(requestConfig); get.setURI(uri); CloseableHttpResponse response = httpClient.execute(get); get.releaseConnection(); return EntityUtils.toString(response.getEntity(), "utf-8"); } catch (ClientProtocolException e) { System.out.println("ClientProtocolException: " + uri.toString()); } catch (IOException e) { throw new IllegalRequestException(ErrorMessageUtil.RECOMMEND_TIMEOUT); } return ""; }
这样我每次调用的时候直接new出一个新的HttpGet请求,就完事了,并发数调高了一倍都没有再报错
太自觉得是就是由于我查看了PoolingHttpClientConnectionManager和CloseableHttpClient,都是线程安全的,结果忽略的HttpGet,根本就没考虑这个请求的线程安全问题,明明源码里都标明了
@NotThreadSafe public class HttpGet extends HttpRequestBase
备忘下,httpclient里继承自HttpRequestBase的Method都是非线程安全的
ps:多线程里每次还要new个新的HttpGet,有没有大牛有好办法解决?