多线程批量上传excel

  多线程处理批量上传excel解析后入库操作

思路:上传文件文件控制在200以内,每个文件对应一个订单,多线程处理上传的文件,每个线程处理一部分,最后在合并结果,返回前端展示。

  • 步骤1:任务划分,根据文件数量算出需要启用的线程数,然后使用栈存放List的下标
  • 步骤2:处理业务,每个线程执行完成后收集结果,使用CountDownLatch计数;使用Map,key对应存储线程id,value存储线程的处理结果
  • 步骤3:合并结果,合并处理Map的结果,返回结果
        public Result importMultipleExcel2(MultipartHttpServletRequest request){
            
            //开始时间
            long time1 = System.currentTimeMillis();
            
            Iterator<String> fileNames = request.getFileNames();
            Map<Thread, List<Map<String, Object>>> threadData = new HashMap<>();
            Map<Thread, Integer> successData = new HashMap<>();
            Map<Thread, Integer> failData = new HashMap<>();
            try {
                while (fileNames.hasNext()) {
                    List<MultipartFile> fileList = request.getFiles(fileNames.next());
                    if (fileList.size() > 0) {
                        //文件数量
                        int size = fileList.size();
                        //每个线程处理的文件数量
                        final int number = 30;
                        //开启的线程数
                        int count = size % number == 0 ? (size / number) : (size / number + 1);
                        //初始化线程池
                        ExecutorService executor = Executors.newFixedThreadPool(count);
                        //创建计数器
                        CountDownLatch end = new CountDownLatch(count);
                        //分配要处理的任务
                        Stack <Map<Integer, Integer>> stack = new Stack<>();
                        for(int i=0;i<count;i++){
                            final int from = i * number;
                            final int to = (i + 1) * number > size ? size : (i + 1) * number;
                            
                            Map<Integer, Integer> map = new HashMap<>();
                            map.put(from, to);
                            stack.push(map);
                        }
                         //为每个线程分配要执行的数据
                         for(int i=0;i<count;i++){
                            executor.execute(()->{
                                try {
                                    Map<Integer, Integer> kvmap = stack.pop();
                                    logger.debug("kvmap:"+kvmap);
                                    kvmap.forEach((key , value)->{
                                        List<Map<String, Object>> list = new ArrayList<Map<String, Object>>();
                                        int success = 0;
                                        int fail = 0;
                                        for (int n = key; n < value; n++) {
                                            Result result = 处理导入excel的业务方法;
                                            String orFileName = fileList.get(n).getOriginalFilename();
                                            if (result.get("code").toString().equals("0")) {
                                                success = success + 1;
                                            } else {
                                                fail = fail + 1;
                                                Map<String, Object> params = new HashMap<String, Object>();
                                                params.put("fileName", orFileName);
                                                params.put("status", result.get("msg"));
                                                params.put("code", "1");
                                                list.add(params);
                                            }
                                        }
                                        threadData.put(Thread.currentThread(), list);
                                        successData.put(Thread.currentThread(), success);
                                        failData.put(Thread.currentThread(), fail);
    
                                });
                                    
                                }catch (Exception e) {
                                    e.printStackTrace();
                                }finally {
                                    end.countDown();  
                                }
                            });
                         }
                         end.await();
                         //关闭线程池
                         executor.shutdown();
                    }
                }
            } catch (Exception e) {
                e.printStackTrace();
                throw new SysAdminServiceException("导入文件失败");
            }
    
            // 合并处理每个线程的数据
            Integer[] success = {0};
            Integer[] fail = {0};
            List<Map<String, Object>> list = new ArrayList<>();
            successData.forEach((key, value) -> {
                success[0] = success[0] + value;
            });
            failData.forEach((key, value) -> {
                fail[0] = fail[0] + value;
            });
            threadData.forEach((key, value) -> {
                list.addAll(value);
            });
            
            long time2 = System.currentTimeMillis();
            System.out.println("总耗时:"+(time2-time1));
            return Result.ok().put("msgList", list).put("cheng", success[0]).put("importMsg", fail[0]);
        }

     CountDownLatch:主要使用场景一个线程等待多个线程执行完毕后再执行

posted @ 2020-10-16 15:51  华格瑞沙  阅读(512)  评论(0编辑  收藏  举报