• 首页
  • 邻居
  • 关于
  • 归档
  • 搜索
  • 夜间模式
    ©2020-2026  我的学习笔记 Theme by OneBlog

    我的学习笔记博客

    搜索
    标签
    # 随笔 # Java # 教程 # openwrt # Mysql # SQL # 爬虫 # post # Js调优 # MAVEN
  • 首页>
  • 随笔>
  • 正文
  • 多线程处理大数据量查询

    2024年04月03日 916 阅读 0 评论 2445 字

    最近在实现一个导入功能,数据量在5w左右,后续会持续增长,使用的是easyExcel,读取文件性能较好,但因为每条数据都要做复杂的数据校验,导致整体响应时间在三四十分钟,虽然说导入不是直接和用户交互,但现在数据量不算很大的情况下,这个响应时间还是需要优化的,读取文件速度在几秒以内,主要是在数据校验这块,所以就使用了多线程去工作。

    主要代码:

    import java.util.concurrent.*;
    public class Test{
    private static final int threadNum = Runtime.getRuntime().availableProcessors()*2;// 获取cpu核数
    public void syncData(List<NewRegionReq> regionList) throws ExecutionException, InterruptedException {
            /**
             * 多线程分析数据
             */
            List<Future> list = new ArrayList<>();
            ExecutorService executor = Executors.newFixedThreadPool(threadNum);
            int num = (regionList.size() / threadNum) + 1;  //计算每个线程需要处理的记录数
            for (int j = 0; j < threadNum; j++) {
                //读取数据的起始位置
                int startNum = j * num;
                //读取数据的结束位置
                int endNum = startNum + num;
                //添加任务
                Callable<String> task = new ThredQuery(regionList, startNum, endNum);
                Future f = executor.submit(task);
                //接受返回结果
                list.add(f);
            }
            // 关闭线程池
            executor.shutdown();
            for (Future f : list) {
                // 从Future对象上获取任务的返回值,并输出到控制台
                System.out.println(f.get().toString()); //OPTION + return 抛异常
            }
            newRegionMapper.save(regionList);
            log.info("共导入数据 {} 行", regionList.size());
        }
    
    class ThredQuery implements Callable<String> {
            private List<NewRegionReq> regionList;
            private int startNum;
            private int endNum;
    
            public ThredQuery(List<NewRegionReq> regionList, int startNum, int endNum) {
                this.regionList = regionList;
                this.startNum = startNum;
                this.endNum = endNum;
                //System.out.println(startNum + "\t" + endNum);
            }
    
            @Override
            public String call() {
                for (int i = startNum; i < endNum; i++) {
                    //自己的业务逻辑
                    //if (i < regionList.size()) {
                   //}
                }
                return "成功";
            }
        }
    }
    

    思路:
    1:先计算出查询总量,根据服务器的cpu核数,求每个线程应处理的条数
    2.使用Callable返回结果,然后聚合数据,最后处理。

    这里有个问题就是线程池合理的线程数你是如何考虑的?这也是之前面试遇到的一个题:

    1.先看下机器的CPU核数,然后在设定具体参数:

    System.out.println(Runtime.getRuntime().availableProcessors());

    即CPU核数 = Runtime.getRuntime().availableProcessors()

    2.分析下线程池处理的程序是CPU密集型,还是IO密集型

    CPU密集型:核心线程数 = CPU核数 + 1

    IO密集型:核心线程数 = CPU核数 * 2

    本文著作权归作者 [ admin ] 享有,未经作者书面授权,禁止转载,封面图片来源于 [ 互联网 ] ,本文仅供个人学习、研究和欣赏使用。如有异议,请联系博主及时处理。
    取消回复

    发表留言
    回复

    首页邻居关于归档
    Copyright©2020-2026  All Rights Reserved.  Load:0.017 s
    京ICP备18019712号
    Theme by OneBlog V3.6.5
    夜间模式

    开源不易,请尊重作者版权,保留基本的版权信息。