天天看點

多線程解決excel資料多上傳問題

excel名單人數過多,超多140000條,單個線程處理問題,已經不能滿足需求,需要做多線程的優化。再一點就是多個線程導入需要給是否導入成功的标志。
  
  首先,上傳excel根據業務校驗excel,這個部分省略,可以查上傳excel和校驗的相關知識。
  其次,就是怎麼将整個excel分拆成各個小的部分,然後分線程上傳。      

A、将excel全部加載在記憶體list中(batchParams)

//存儲傳回導入成功的條數
int countSuceeNumber=0;    
    //将全部excel記錄發送多線程線程方法,批量導入資料
        try{
        countSuceeNumber=saveBaseInfoList(batchParams); 
        }catch(Exception e){
            e.printStackTrace();
        }      

B、定義方法,多線程将excel的資料存儲起來

/**
   * 多線程批量存儲資料
   * @param batchParams
   * @return
   */
  public int saveBaseInfoList(List batchParams){
    int count=999;//根據數量确定一個線程處理多少條資料
      int listSize=batchParams.size();
      if(listSize>=1 && listSize<1000){
        count=333;
      }else if(listSize>=1000 && listSize<10000){
        count=1333;
      }else if(listSize>=10000 && listSize<30000){
        count=2333;
      }else if(listSize>=30000){
        count=3333;
      }
      //計算開啟的線程數
      int runThreadSize=(listSize/count)+1;
      logger.info("開啟的線程數量"+runThreadSize);
      //存放每個線程的執行資料
      List newList=null;
      //建立一個線程池,數量和開啟線程數一樣
      ExecutorService executor=Executors.newFixedThreadPool(runThreadSize);
      //存放傳回結果集
      int successCountNumber=0;
      //定義completionService
      CompletionService<Integer> completionService=new ExecutorCompletionService<Integer>(executor);
      try{
      //循環建立線程
      for(int i=0;i<runThreadSize;i++){
        if((i+1)==runThreadSize){
          int startIndex;
          startIndex=(i*count);
          int endIndex=listSize;
          newList=batchParams.subList(startIndex, endIndex);
        }else{
          int startIndex=(i*count);
          int endIndex=((i+1)*count);
          newList=batchParams.subList(startIndex, endIndex);
        }
        createBatchInsertThread(completionService,newList);
      }
      //采用completionService.take(),内部維護阻塞隊列,任務先完成的先擷取到
      for(int i=0;i<runThreadSize;i++){
        Integer counts=completionService.take().get();
        successCountNumber+=counts;
      }
      logger.info("成功的條數"+successCountNumber);
    }catch(Exception e){
      e.printStackTrace();
    }finally{
      executor.shutdown();
    }
      return successCountNumber;
  }      

C、調用多線程的執行類

private  Future<Integer> createBatchInsertThread(CompletionService<Integer> completionService,List newList) throws Exception{
    BatchInsertThread batchinsertThread=new BatchInsertThread(newList);
    @SuppressWarnings("unchecked")
    Future<Integer> submit = completionService.submit(batchinsertThread);
    return submit;
  }      

D、callable()的具體執行類

public class BatchInsertThread implements Callable<Integer>{
  
   
   private BaseService baseService = (BaseService) SpringContextHolder.getApplicationContext().getBean("baseService"); 
   private Logger logger = Logger.getLogger(getClass());
   List list;
  
   public BatchInsertThread(){
     
   }
   
   public BatchInsertThread(List list){
     this.list=list;
    
   }

  @Override
  public Integer call() throws Exception {
    try{
       logger.info("本次導入人數的大小"+list.size());
       baseService.batchInsert(list);
     }catch(Exception e){
       e.printStackTrace();
       logger.error(e.getMessage());
     }
    return list.size();
  }
   
}      
@Service
public class BaseServiceImpl implements BaseService{

  @Resource
  private IAthleteScoreDao athleteScoreDao;
  
  @Override
  public void batchInsert(List list) throws Exception{
     Map<String, Object>[] paramArrayOfMap=(Map[])list.toArray(new HashMap[list.size()]);
         athleteScoreDao.batchAddAthleteScore(paramArrayOfMap);
  }

}      

繼續閱讀