• CountDownLatch使用错误+未最终断开连接导致线程池资源耗尽


    错误描述:

            我设置了CountDownLatch对线程的协作做出了一些限制,但是我发现运行一段时间以后便发现定时任务不运行了。

    具体代码:

    1. public void sendToCertainWeb() throws IOException, InterruptedException {
    2. List urlList = scheduleplanMapper.getRandomUrlList();
    3. Thread.sleep(6000);
    4. CountDownLatch countDownLatch = new CountDownLatch(20);
    5. for (String s : urlList) {
    6. transportThreadPool.execute(()->{
    7. try {
    8. URL url = new URL(s);
    9. // 打开连接
    10. HttpURLConnection connection = (HttpURLConnection) url.openConnection();
    11. // 设置请求方法为GET
    12. connection.setRequestMethod("GET");
    13. connection.setConnectTimeout(100000);
    14. connection.setReadTimeout(100000);
    15. // 添加自定义的请求头信息
    16. String agent = scheduleplanMapper.getRandomAgent();
    17. connection.addRequestProperty("User-Agent", agent);
    18. connection.addRequestProperty("Accept-Language", "en-US,en;q=0.9");
    19. // 获取服务器返回的状态码
    20. int responseCode = connection.getResponseCode();
    21. if (responseCode == HttpURLConnection.HTTP_OK) {
    22. // 读取服务器返回的数据
    23. BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream()));
    24. String line;
    25. StringBuilder response = new StringBuilder();
    26. while ((line = reader.readLine()) != null) {
    27. response.append(line);
    28. }
    29. reader.close();
    30. log.info("Right Code: " + responseCode);
    31. } else {
    32. log.error("Error Code: " + responseCode);
    33. }
    34. // 关闭连接
    35. connection.disconnect();
    36. countDownLatch.countDown();
    37. }catch (Exception e){
    38. log.error(JSON.toJSONString(e));
    39. }
    40. });
    41. }
    42. countDownLatch.await();
    43. }

    报错以后定时任务不运行了 

    错误排查:

     打印线程日志发现定时任务的线程在第86行代码停着不动了。

    正常的线程日志应该是这样的。

    查看第86行代码,发现这里并没有唤醒主线程 ,导致线程一直处于运行状态,无法继续下一个任务。

            错误的原因是countDownLatch.countDown()并没有放在finally块里因此发生了错误并不会走这块代码,导致线程没有countDown

    错误修改:

    把countDownLatch.countDown();放在finally代码块里保证一定会进行countDown这个动作

    正确代码:

    1. public void sendToCertainWeb() throws IOException, InterruptedException {
    2. List urlList = scheduleplanMapper.getRandomUrlList();
    3. Thread.sleep(6000);
    4. CountDownLatch countDownLatch = new CountDownLatch(20);
    5. for (String s : urlList) {
    6. transportThreadPool.execute(()->{
    7. try {
    8. URL url = new URL(s);
    9. // 打开连接
    10. HttpURLConnection connection = (HttpURLConnection) url.openConnection();
    11. // 设置请求方法为GET
    12. connection.setRequestMethod("GET");
    13. connection.setConnectTimeout(100000);
    14. connection.setReadTimeout(100000);
    15. // 添加自定义的请求头信息
    16. String agent = scheduleplanMapper.getRandomAgent();
    17. connection.addRequestProperty("User-Agent", agent);
    18. connection.addRequestProperty("Accept-Language", "en-US,en;q=0.9");
    19. // 获取服务器返回的状态码
    20. int responseCode = connection.getResponseCode();
    21. if (responseCode == HttpURLConnection.HTTP_OK) {
    22. // 读取服务器返回的数据
    23. BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream()));
    24. String line;
    25. StringBuilder response = new StringBuilder();
    26. while ((line = reader.readLine()) != null) {
    27. response.append(line);
    28. }
    29. reader.close();
    30. log.info("Right Code: " + responseCode);
    31. } else {
    32. log.error("Error Code: " + responseCode);
    33. }
    34. // 关闭连接
    35. connection.disconnect();
    36. }catch (Exception e){
    37. log.error(JSON.toJSONString(e));
    38. }finally {
    39. countDownLatch.countDown();
    40. }
    41. });
    42. }
    43. countDownLatch.await();
    44. }

    错误总结:

             我们一般认为线程处于blocked状态的时候线程才是处于阻塞状态,但是这个状态只是对于计算机来说的。对于我们来说,只要业务不执行了,线程就是处于阻塞状态的,因此任何状态下的线程对于业务来说都是阻塞的。 我这个项目是爬虫项目,会去爬取别人网站的数据,有些网站识别爬虫之后不仅会拒绝你访问,还会通过一直不给响应使得你的服务器线程占满,进而导致你的爬虫服务器崩溃。

    参考文章: 

    未设置超时时间导致线程池资源耗尽,排查过程-CSDN博客

  • 相关阅读:
    Linux下ipcalc命令详解及C/C++实现(计算主机的IP信息)
    docker安装redis
    C++中的智能指针
    坚持用C++刷牛客题(剑指offer专题)
    数组常用的方法介绍及使用及频率度(17个)
    万字博客带你全面剖析Spring的依赖注入
    Vue - 得到组件渲染的DOM
    【python练习】python斐波那契数列超时问题
    浅浅探索Memcached
    计数排序与基数排序
  • 原文地址:https://blog.csdn.net/weixin_55229531/article/details/138108063