httpclient4 多线程请求RetryExec I/O exception 问题解决

本身封装了一个请求类,因为本身写的时候太自觉得是,致使多线程请求的时候报错 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,有没有大牛有好办法解决?

相关文章
相关标签/搜索