多线程批量上传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:主要使用场景一个线程等待多个线程执行完毕后再执行