惊宇 2024-07-30 10:01 采纳率: 50%
浏览 89
已结题

多线程+连接池+代理 运行一段时间线程阻塞

使用多线程+httpClient连接池+ip代理 请求第三方接口。运行一段时间 出现线程阻塞的情况。目前看线程阻塞都在一个调用的请求里面。


```java
    @Retryable(
            value = {Exception.class}, // 指定哪些异常需要重试
            maxAttempts = 3,          // 重试次数
            backoff = @Backoff(delay = 3000) // 每次重试间隔2秒
    )
    @ApiLog(title = "XXXX",businessType = "拼接cookie请求第一部分",resultType = false)
    public String disneyByCookies01(String token) throws IOException {

        RequestConfig requestConfig = RequestConfig.custom()
//                .setSocketTimeout(10000)
//                .setConnectTimeout(10000)
                .setRedirectsEnabled(false)
                .build();
        HttpGet httpGet = new HttpGet("https://XXXXXXXX.cn/XXX/XXXXXX-svc-gw/api/auth_code/authorize/v1?activity_code=6119&redirect_type=0&redirect_uri=https://XXXX.activity-24.m.duiba.com.cn/customShare/share?id=Did1NTcxODM&");
        httpGet.setConfig(requestConfig);
        httpGet.setHeader("User-Agent", "Mozilla/5.0 (Linux; Android 10; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/101.0.4951.74 Mobile Safari/537.36");
        httpGet.setHeader("Cookie", "piXX-m-sid=" + token + "; platform=8; app_version_code=282; app_version_name=5.1.9; app_device_type=android");
        httpGet.setHeader("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9");
        // 执行请求并获取响应
        HttpResponse response = httpClient.execute(httpGet);
        int statusCode = response.getStatusLine().getStatusCode();
        Header contentTypeHeader = response.getFirstHeader("Location");
        String location = contentTypeHeader.getValue();
        String accessCode = null;
        if (location != null) {
            String regex = "&access_code=([^&]*)";
            Pattern pattern = Pattern.compile(regex);
            Matcher matcher = pattern.matcher(location);
            if (matcher.find()) {
                accessCode = matcher.group(1); // 提取匹配组中的access_code值
                log.info("【success】[线程:" + threadName + "]拼接cookie请求第一部分请求成功" + accessCode);
            }
        } else {
            log.info("【error】[线程:" + threadName + "]拼接cookie请求第一部分请求异常response中获取location失败" + response);
            throw new IllegalStateException("【error】[线程:" + threadName + "]拼接cookie请求第一部分请求异常response中获取location失败");
        }
        return accessCode;

```

  • 写回答

22条回答 默认 最新

  • 专家-皆知 2024-07-30 10:10
    关注

    引自免费微信小程序皆我百晓生

    从您提供的代码来看,有几个可能的原因会导致线程阻塞的问题:

    1. 未处理的异常或错误:

      • 如果httpClient.execute()方法抛出了异常(例如IOException),并且这些异常没有被捕获和处理,那么线程可能会在该点阻塞。
    2. 连接池配置不当:

      • 如果连接池的配置不正确(例如最大连接数、空闲连接数等),这可能导致连接耗尽,从而导致线程阻塞等待新的连接。
    3. 超时设置缺失:

      • 您注释掉了RequestConfig中的超时设置。如果网络请求非常慢或者服务器无响应,那么线程将会无限期地等待响应,从而导致阻塞。
    4. 资源泄露:

      • 如果HttpResponse没有被适当地关闭,可能会导致资源泄露,并且影响连接池的可用性。
    5. 重试策略:

      • 使用@Retryable注解进行重试时,如果重试逻辑设计不合理(例如无限重试或重试间隔过短),可能会导致线程阻塞。

    针对上述问题,您可以考虑以下改进措施:

    1. 异常处理

    确保捕获所有可能的异常,并采取适当的措施来处理它们,比如记录日志或者重新抛出异常。

    2. 超时设置

    RequestConfig添加合理的超时设置:

    RequestConfig requestConfig = RequestConfig.custom()
        .setSocketTimeout(10000)
        .setConnectTimeout(10000)
        .setRedirectsEnabled(false)
        .build();
    

    3. 连接池管理

    确保您的连接池配置合理,并且能够适应并发请求的压力。例如,可以使用PoolingHttpClientConnectionManager来管理连接池。

    4. 资源释放

    确保关闭所有的HttpResponsehttpGet请求:

    try (CloseableHttpResponse response = httpClient.execute(httpGet)) {
        // 处理响应
    } catch (IOException e) {
        log.error("发生IO异常", e);
    }
    

    5. 重试逻辑

    检查重试逻辑是否合理,确保不会导致无限循环或短时间内大量重复请求。

    6. 使用代理

    如果您正在使用代理,请确保代理是可靠的,并且能够处理高并发请求。

    7. 日志记录

    增加详细的日志记录,以便于追踪问题。

    如果您可以提供更多关于系统架构的信息,我们可以更具体地分析问题所在。此外,如果您可以提供线程堆栈跟踪信息,那将更有助于定位问题。

    评论

报告相同问题?

问题事件

  • 已结题 (查看结题原因) 8月4日
  • 创建了问题 7月30日