性能优化实战使用CountDownLatch

这篇具有很好参考价值的文章主要介绍了性能优化实战使用CountDownLatch。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

1.分析问题

原程序是分页查询EventAffinityScoreDO表的数据,每次获取2000条在一个个遍历去更新EventAffinityScoreDO表的数据。但是这样耗时比较慢,测试过30万的数据需要2小时

  private void eventSubjectHandle(String tenantId, String eventSubject) {
    // 查询eventAffinityScoreDO表,更新时间小于今天的(今天更新过的不更新)
    final Integer pageSize = 2000;
    PageResult<EventAffinityScoreDO> groupPag =
        eventAffinityScoreDbService.findByTenantIdAndTimePage(tenantId, eventSubject, 1, pageSize);
    Integer pages = groupPag.getPages();
    Integer pageNum = groupPag.getPageNum();
    while (pages >= pageNum) {
      if (pageNum > 1) {
        groupPag =
            eventAffinityScoreDbService.findByTenantIdAndTimePage(
                tenantId, eventSubject, 1, pageSize);
      }
      List<EventAffinityScoreDO> list = groupPag.getList();
      forEventAffinityScore(tenantId, eventSubject, list);
      if (list.size() < pageSize) {
        break;
      }
      pageNum++;
    }
  }


  private void forEventAffinityScore(
      String tenantId, String eventSubject, List<EventAffinityScoreDO> eventAffinityScoreDOS) {
    eventAffinityScoreDOS.forEach(
        (eventAffinityScoreDO) -> {
         //更新EventAffinityScoreDO表数据
          updateOrAddAffinity(
              tenantId,
              eventAffinityScoreDO.getChatLabsId(),
              eventAffinityScoreDO.getEconomyId(),
              eventAffinityScoreDO.getAttributeValue(),
              eventSubject,
              eventAffinityScoreDO.getAttributeName());
        });
  }

单个线程一个个遍历去更新表数据太慢了,我想把2000的数据分成多份,每份200条,可以分成10份。每份用一个线程去跑。这样跑2000的时间就大大缩短。大概等于跑200个数据的时间。
这里想到使用CountDownLatch

2.知识点CountDownLatch

CountDownLatch 是 Java 中的一个并发工具类,用于在多线程环境中控制线程的执行顺序。它允许一个或多个线程等待其他线程完成操作后再继续执行。
CountDownLatch 的构造方法接受一个整数作为参数,表示需要等待的线程数量。当一个线程完成了自己的任务后,可以调用 countDown() 方法来将计数器减1。当计数器的值变为0时,所有等待的线程都会被释放,可以继续执行。

3.解决问题

我们使用Lists.partition,把2000的集合拆分成每份200的小份,共10分。
CountDownLatch countDownLatch = new CountDownLatch(partition.size())设置CountDownLatch需要等待的线程数为拆分后的份数partition.size(),也就是10份
countDownLatch.countDown(); 每跑完一份计数器减一
countDownLatch.await();计数器减完主程序开始执行,继续循环后面的2000份

 private void eventSubjectHandle(String tenantId, String eventSubject)
        throws InterruptedException {
      // 查询eventAffinityScoreDO表,更新时间小于今天的(今天更新过的不更新)
      final Integer pageSize = 2000;
      PageResult<EventAffinityScoreDO> groupPag =
          eventAffinityScoreDbService.findByTenantIdAndTimePage(tenantId, eventSubject, 1,
   pageSize);
      Integer pages = groupPag.getPages();
      Integer pageNum = groupPag.getPageNum();
      while (pages >= pageNum) {
        if (pageNum > 1) {
          groupPag =
              eventAffinityScoreDbService.findByTenantIdAndTimePage(
                  tenantId, eventSubject, 1, pageSize);
        }
        List<EventAffinityScoreDO> list = groupPag.getList();
        //Lists.partition把list进行拆分,没份200个
        List<List<EventAffinityScoreDO>> partition = Lists.partition(list, 200);
        //设置需要等待的线程数量,就是我们的集合大小
        CountDownLatch countDownLatch = new CountDownLatch(partition.size());
        for (List<EventAffinityScoreDO> eventAffinityScoreDOS : partition) {
          eventSubjectExecutorPool.execute(
              () -> {
                try {
                  forEventAffinityScore(tenantId, eventSubject, eventAffinityScoreDOS);
                } catch (Exception e) {
                  log.info(
                      "AutoAffinityJob updateAffinityByEventSubject error tenantId:{},eventSubject:{}",
                      tenantId,
                      eventSubject,
                      e);
                }
                //每处理完200份计数器减一
                countDownLatch.countDown();
              });
        }
        //计数器减完主程序开始执行,继续循环后面的2000份
        countDownLatch.await();
        if (list.size() < pageSize) {
          break;
        }
        pageNum++;
      }
    }


  private void forEventAffinityScore(
      String tenantId, String eventSubject, List<EventAffinityScoreDO> eventAffinityScoreDOS) {
    eventAffinityScoreDOS.forEach(
        (eventAffinityScoreDO) -> {
          // 根据生态中事件属性属性值更新or新增影响到的内容亲和力
          updateOrAddAffinity(
              tenantId,
              eventAffinityScoreDO.getChatLabsId(),
              eventAffinityScoreDO.getEconomyId(),
              eventAffinityScoreDO.getAttributeValue(),
              eventSubject,
              eventAffinityScoreDO.getAttributeName());
        });
  }

这里需要注意的是如果线程池设置的太小,会导致触发拒绝策略。如果触发了拒绝策略countDownLatch.countDown()就不会执行了。就会导致countDownLatch.await()一直等待。所以这里我把线程池的队列设置的很大Integer.MAX_VALUE,这样不会触发拒绝策略。因为我们最多就10个线程,也不会导致出现OOM

@Configuration
@Slf4j
public class CalculateAffinityThreadPool {

  @Bean(name = "eventSubjectExecutorPool")
  public ExecutorService eventSubjectExecutorPool() {
    int poolSize = ThreadExecutorUtils.getNormalCoreSize();
    return ThreadExecutorUtils.createNormalThreadPool(
        poolSize,
        poolSize,
        0L,
        TimeUnit.MILLISECONDS,
        Integer.MAX_VALUE,
        "eventSubject-pool",
        false);
  }

}

经过测试跑30万的数据只需要20分钟了。文章来源地址https://www.toymoban.com/news/detail-728883.html

到了这里,关于性能优化实战使用CountDownLatch的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【linux高性能服务器编程】项目实战——仿QQ聊天程序源码剖析

    hello !大家好呀! 欢迎大家来到我的Linux高性能服务器编程系列之项目实战——仿QQ聊天程序源码剖析,在这篇文章中, 你将会学习到如何利用Linux网络编程技术来实现一个简单的聊天程序,并且我会给出源码进行剖析,以及手绘UML图来帮助大家来理解,希望能让大家更能了

    2024年04月28日
    浏览(32)
  • nodejs项目实战教程01——http服务和URL类,前端开发社招面试解答之性能优化

    需要在终端重新执行一次node app.js浏览器的内容才会刷新 4.如何获取url中的参数 ============================================================================ 4.1 URL类基础 建议大家可以先看看Node.js API文档中的url 网址部分,这里做简要说明。url字符串在nodejs的url模块,有两种解析API,其中旧版的

    2024年04月11日
    浏览(33)
  • java使用双异步,性能优化

    通过POI读取需要导入的Excel; 以文件名为表名、列头为列名、并将数据拼接成sql; 通过JDBC或mybatis插入数据库; 操作起来,如果文件比较多,数据量都很大的时候,会非常慢。 访问之后,感觉没什么反应,实际上已经在读取 + 入库了,只是比较慢而已。 读取一个10万行的E

    2024年01月23日
    浏览(36)
  • CountDownLatch介绍和使用【Java多线程必备】

    点击   Mr.绵羊的知识星球  解锁更多优质文章。 目录 一、介绍 二、特性 三、实现原理 四、适用场景 五、注意事项 六、实际应用     CountDownLatch 是 Java 中的一个并发工具类,用于协调多个线程之间的同步。其作用是让某一个线程等待多个线程的操作完成之后再执行。它可

    2024年02月05日
    浏览(42)
  • Java并发工具CountDownLatch的使用和原理

    CountDownLatch 允许一个或多个线程等待其他线程完成操作。 假如有这样一个需求:我们需要解析一个 Excel 里多个 sheet 的数据,此时可以考虑使用多线程,每个线程解析一个 sheet 里的数据,等到所有的 sheet 都解析完之后,程序需要提示解析完成。在这个需求中,要实现主线程

    2024年02月16日
    浏览(25)
  • Jmeter性能测试,通过插件监控服务器资源使用情况

    可以通过jmeter 安装\\\"PerfMon(Servers Performance Monitoting)\\\"插件并配合服务端资源监控工具进行实现,详细操作流程如下: (备注:我这个是已安装的,如果未安装,可以点击“Available Plugins”tab搜索该插件) 如果可以选择该元件即代表安装成功 点击AddRow --配置服务器地址、端口号

    2024年02月16日
    浏览(54)
  • 使用CentOS搭建高性能静态HTTP服务器

    在互联网应用中,静态内容是广泛存在的,例如HTML页面、图片、视频等。为了提供高效、稳定和安全的静态内容服务,我们可以使用CentOS来搭建高性能的静态HTTP服务器。 1. 选择合适的软件 Nginx和Apache是两个流行的HTTP服务器软件。Nginx以其高效、轻量级和快速的性能而著称,

    2024年01月23日
    浏览(51)
  • 【Java】Java中使用HashMap优化多层for循环嵌套以及for循环之性能优化

    for循环是开发时常用的语法之一,比如对数组,集合的遍历等,但是如果使用不好也会出现很多新能损耗的问题,今天就来讲解一下for循环的常用性能优化问题。 for循环 里面还有 for循环, 然后做一些数据匹配、处理 这种场景。 m层嵌套的n次的for循环的时间复杂度为O(n^m),

    2024年02月16日
    浏览(32)
  • Jmeter性能测试 —— jmeter之使用ServerAgent监控服务器

    ServerAgent 性能测试时我们关注的重要指标是:并发用户数,TPS,请求成功率,响应时间,服务器的CPU,memory, I/O disk等。Jmeter的聚合报告可以查看并发数、吞吐量、请求成功率、响应时间等;如果要查看服务器端的CPU,memory, I/O disk等就需要安装插件ServerAgent 将ServerAgent-2.2

    2024年02月07日
    浏览(44)
  • 【vite+vue3.2 项目性能优化实战】使用vite-plugin-cdn-import进行CDN加速优化项目体积

    CDN (Content Delivery Network)即内容分发网络,是一种通过在全球范围内分布式部署服务器来加速网络内容传输的技术。CDN加速的原理是,当用户请求访问某个资源时, CDN会根据用户的地理位置和网络状况,自动选择离用户最近的服务器来响应请求 。如果该服务器上已经缓存了

    2024年02月03日
    浏览(31)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包