多线程使用之主线程与多线程响应同步
来源:互联网 发布:施乐2011网络设置 编辑:程序博客网 时间:2024/06/03 19:31
需求:
导出数据10000条数据到excel表中。希望用多线程优化导出速度。
设计:
将10000条数据分成10份。用10个线程分别给excel写值分10个sheet页问题:
导出数据时,由于写值启动了多线程,导出数据为空excel表格问题的梳理:
由于启动了多线程,多线程的意义是不影响主线程的响应速度,这样导致的问题是response响应给excel表了,但是值还没有写入,产生了空表解决方法:
当所有多线程执行完毕之后主线程再响应前台
注意事项:此方法不可以使用可缓存线程池去创建的多线程。这里使用的可设置数量的多线程池
代码controller 这个类是提前获取到输出流,当方法执行完毕时自动响应前台下载的文件
@RequestMapping("/common/cuijiDownLoad")public void cuijiDownLoad(CaseHead caseHead, CuijiDownLoadEx cuijiDownLoadEx, HttpServletRequest request, HttpServletResponse response, HttpSession session, CaseHead head, CaseParamsExtend exParams, @RequestParam(value = "type", defaultValue = "-1") Integer type) {response.setCharacterEncoding("UTF-8");// 设置相应内容的编码格式// 设置导出文件文件名String name = "案件催记";name = name + fmt.format(new Date());OutputStream os = null;String companycode = SessionUtil.getCompnayCodeFromSessionByCuishouAdminOrUser(session);try {String fname = name + ".xls";fname = CompanyadminController.toUtf8String(request, fname);response.reset();// 清空输出流response.setHeader("Content-Disposition", "attachment;filename=" + fname);response.setContentType("application/msexcel");// 定义输出类型os = response.getOutputStream();// 取得输出流commonService.toExcelCuijiByCaseHead(os, caseHead, cuijiDownLoadEx);//方法} catch (Exception e) {e.printStackTrace();} finally {if (os != null) {try {os.close();} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}}}}
这里放入自定义等分list的方法
/** * 将一个list均分成n个list,主要通过偏移量来实现的 * @param maps * @return */ public static List<List<Map<String, Object>>> averageAssign(List<Map<String, Object>> maps,int n){ List<List<Map<String, Object>>> result=new ArrayList<List<Map<String, Object>>>(); int remaider=maps.size()%n; //(先计算出余数) int number=maps.size()/n; //然后是商 int offset=0;//偏移量 for(int i=0;i<n;i++){ List<Map<String, Object>> value=null; if(remaider>0){ value=maps.subList(i*number+offset, (i+1)*number+offset+1); remaider--; offset++; }else{ value=maps.subList(i*number+offset, (i+1)*number+offset); } result.add(value); } return result; }
判断线程完全执行完的代码
exec.shutdown(); while(true){ if(exec.isTerminated()){ writer.write("---END---\n"); writer.close(); System.out.println("所有的子线程都结束了!"); break; } Thread.sleep(1000); }exe.shutdown();该方法在加入线程队列的线程执行完之前不会执行。
exe.isTerminated();当shutdown()或者shutdownNow()执行了之后才会执行,并返回true。
在上面的代码中必须有exe.isTerminated()的判断,否则在投入5个线程到线程池后会直接打印:“结束了”。不能达到我们想要的效果。
通过while(true)循环判断exe.isTerminated()重生之大文豪的值,为了防止过多的判断浪费资源,可设置线程睡眠Thread.sleep(200);
正是由于这个睡眠,所以当所有线程池中的线程都执行完后,有可能延迟200ms才执行"结束了"语句。这个参数越小延迟越小,结果越准确。
具体使用场景:
public void subMapListAndDownload(final OutputStream os,final String[] fieldHeadName, final String[] dataName,final List<Map<String, Object>> maps){ //将listmap分份 List<List<Map<String, Object>>> maplist=new ArrayList<List<Map<String, Object>>>(); if (maps.size() <1000){ //不分份 maplist.add(maps); }else if (maps.size() >=1000 && maps.size() <2000 ){ //两等分 maplist= averageAssign(maps,2); }else if (maps.size() >=2000 && maps.size() <3000 ){ //三等分 maplist= averageAssign(maps,3); }else if (maps.size() >=3000 && maps.size() <4000 ){ //四等分 maplist= averageAssign(maps,4); }else if (maps.size() >=4000 && maps.size() <5000 ){ //五等分 maplist= averageAssign(maps,5); }else if (maps.size() >=5000 && maps.size() <6000 ){ //六等分 maplist= averageAssign(maps,6); }else if (maps.size() >=6000 && maps.size() <7000 ){ //七等分 maplist= averageAssign(maps,7); }else if (maps.size() >=7000 && maps.size() <8000 ){ //八等分 maplist= averageAssign(maps,8); }else if (maps.size() >=8000 && maps.size() <9000 ){ //九等分 maplist= averageAssign(maps,9); }else if (maps.size() >=10000 ){ //十等分 maplist= averageAssign(maps,10); } // 创建一个webbook,对应一个Excel文件 final HSSFWorkbook wb = new HSSFWorkbook(); //将分完份的按份数设置线程 ExecutorService cachedThreadPool = Executors.newFixedThreadPool(maplist.size()); //固定数量的线程池 for (int i = 0; i <maplist.size() ; i++) { final List<Map<String, Object>> maps1=maplist.get(i); //ExcelFile.writeExcelIncludeData(os, fieldHeadName, dataName, maps1); cachedThreadPool.execute(new Runnable() { public void run() { if (os != null && fieldHeadName != null && dataName != null && maps1 != null) ExcelFile.writeExcelIncludeDataSheet(os, fieldHeadName, dataName, maps1,wb); } }); } boolean over=false; cachedThreadPool.shutdown(); while (true) { if (cachedThreadPool.isTerminated()) { System.out.println("结束了!"); over=true; if (over != true){ try { Thread.sleep (3000) ; } catch (InterruptedException e) { e.printStackTrace(); } } break; } } try { wb.write(os); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } }
给excel添加sheet和值的方法
/** * 导出表头和数据 * * @param oupOutputStream * @param fieldName * @param mapList */public static void writeExcelIncludeDataSheet(OutputStream oupOutputStream, String[] fieldName,String[] dataName, List<Map<String, Object>> mapList, HSSFWorkbook wb ) {// 在webbook中添加一个sheet,对应Excel文件中的sheetHSSFSheet s = wb.createSheet();createTagAndData(fieldName,dataName, s,mapList);// 写表格的头部// 创建单元格,并设置值表头 设置表头居中HSSFCellStyle style = wb.createCellStyle();style.setAlignment(HSSFCellStyle.ALIGN_CENTER); // 创建一个居中格}
private static void createTagAndData(String[] tags,String[] dataName,HSSFSheet s,List<Map<String, Object>> mapList){HSSFRow row = s.createRow(0);HSSFCell cell = null;for (int i = 0; i < tags.length; i++) {cell = row.createCell(i);cell.setCellValue(tags[i]);}for(int i=1;i<=mapList.size();i++){row = s.createRow(i);cell = null;for (int s1 = 0; s1 < tags.length; s1++) {cell = row.createCell(s1);if(mapList.get(i-1).get(dataName[s1])!=null){cell.setCellValue(mapList.get(i-1).get(dataName[s1]).toString());}}}}
多线程之路漫漫,还要不段摸索
感谢观看
阅读全文
0 0
- 多线程使用之主线程与多线程响应同步
- 多线程之主线程与子线程
- C++拾遗--多线程:主线程与子线程的同步
- 多线程之主线程等待多线程
- 多线程之杀死主线程。。
- Win32多线程之主线程
- java 多线程之主线程与子线程
- QT中的多线程-与主线程通信
- Python 多线程,主线程与子线程
- 多线程之同步与死锁
- 多线程之同步与锁
- 多线程同步问题:主线程不能进入临界区
- C++简单多线程事件驱动同步通知到主线程
- c++11多线程之主线程与子线程数据传输与共享
- 多线程中静态变量使用要注意!!!主线程与子线程关系。
- 多线程开发(主线程)
- java多线程中子线程与主线程进行轮换
- Java多线程之同步与死锁
- 转:交叉验证在sklearn中的实现
- 一个简单的计时器
- 给初学者的RxJava2.0教程(二)
- dvaJs + react 快速构建项目
- 基于Sentinel的Redis集群(主从&Sharding)的redis封装实现
- 多线程使用之主线程与多线程响应同步
- Perl CPAN install PM package
- a-web-crawler-with-asyncio-coroutines
- MySQL添加用户、删除用户与授权
- ZXing笔记(1)—Hello ZXing
- c231n notes list
- C#中的Path类的方法详解
- django模板继承常用标签和规则(看django源码遇到了{{ block.super }})
- spring security 自定义认证登录