今天是2018.03.22,已经很久没有更新博客了。。这段时间一直挺忙的,也收获很多。最近一个excel导出的任务让我搞了好久,想想踩过的坑,就想上来小结一番。
------------------------------------------------------分割线------------------------------------------------------
前沿:对于Java党而言,poi是目前较为流行的对Microsoft Office格式档案读和写的功能的工具。但有时候单线程写一个数据量需求较大或较为耗时(如向excel写图片)的文件时,
如导出,往往太慢而超时。本文将以多线程导出一个excel文件为例(同一个sheet)来提高效率。
1.线程与任务
线程池:可以用线程池来管理线程,包括任务的分配和线程的回收。
任务:每个线程待处理的资源,在submit任务时,需保证每个任务不会互相重复。
线程:任务的执行者
(注:任务和线程的概念一定要区分开来!每个线程可以在执行完一次任务后,继续执行还未被处理的任务。线程池submit一个任务不代表会有一个线程立即去执行它)
如何保证所有任务都被执行完,才能够进行IO流的写入操作?
保证所有任务都执行完毕,可以用一个同步工具类:CountDownLatch来记录,初始化它的时候,size是任务数,每执行一次,就countDown。在所有任务执行完毕的代码逻辑后await,
即可防止还有任务没被线程执行完就往下执行,起到阻塞和等待的作用。
2.思路流程
首先,一个excel对象在poi里被定义为Workbook, 一个Workbook包含多个Sheet. 每个Sheet有Row, 每行又有Cell(单元格).
先把要往Sheet里写的所有数据按行区分,即先准备好要填充的数据集合(元素是每行的对象,代码略);
建立线程池,管理线程和分配任务:
ExecutorService es = Executors.newFixedThreadPool(40);
//线程执行任务的计数器,初始大小为待填充数据集的size
CountDownLatch latch = new CountDownLatch(results.size());
for(int i=0; i<results.size(); i++) {
ExcelResultVo excelResultVo = results.get(i);
// RowObj rowObj = groups.get(i);
es.submit(new Runnable() {
@Override
public void run() {
PoiWrite.writeData(excelResultVo, wb, sheet, patriarch, styleContent);
latch.countDown();//每个任务执行完就countDown一次
}
});
}
latch.await();//阻塞,直到计数器的值为0,才让主线程往下执行
es.shutdown();//关闭线程池
因为操作的是同一个sheet,而sheet在addRow的时候底层是这样做的:
public void insertRow(RowRecord row) { // Integer integer = Integer.valueOf(row.getRowNumber()); _rowRecords.put(Integer.valueOf(row.getRowNumber()), row); // Clear the cached values _rowRecordValues = null; if ((row.getRowNumber() < _firstrow) || (_firstrow == -1)) { _firstrow = row.getRowNumber(); } if ((row.getRowNumber() > _lastrow) || (_lastrow == -1)) { _lastrow = row.getRowNumber(); } }
/_rowRecords是一个Map<Integer, RowRecord>,而Map是线程非安全的,所以需要在addRow的时候加锁:
public static synchronized HSSFRow getRow(HSSFSheet sheet, int rownum) { return sheet.createRow(rownum); }
另:往excel写图片需要图片的byte数组(图片的url地址转byte数组也比较耗时,可以用多线程先准转好,作为填充数据的一个属性),这里其实也是先createRow,再往指定单元格写图片了,大致语法:
HSSFClientAnchor anchor = new HSSFClientAnchor(0, 0,0 , 0, (short) col1, row1, (short) col2, row2);//这里其实createRow了 HSSFPicture pict = patriarch.createPicture(anchor, wb.addPicture(imgData, HSSFWorkbook.PICTURE_TYPE_JPEG)); pict.resize(1.0,1.0);
所以写图片的方法也需要同步,不然会报错。。(血的教训)
经测试:单线程导出1000条数据(含1100张图片)需超过5min的时间,很容易超时。而多线程仅需20s以内!
注:一定要注意多线程操作同一对象的线程安全问题,如多线程操作同一List,一定要用线程安全的List如CopyOnWriteArrayList或用Collections.synchronizedList包装原始的ArrayList。
add的时候才能避免线程安全问题。
思考:之前一直对多线程停留在概念的理解上,实践的还较少,现在对于线程安全有更为直观的理解:是否不同线程执行了不同的资源(任务)而没有发生“多个线程重复执行同一资源”
的情况?比如本文的例子,是先把同一个sheet待填充的数据按Row划分,每个任务指定了Row的位置,每个线程负责将每行数据填充到指定位置而不会发生重复填充某一行的情况。这样多个线程执行
一个“大任务”划分出来的每个“小任务”,就能达到节省时间的目的。
相关推荐
对大数据量的导出excel,用多线程,用倒数计数器对文件进行生成,使用poi,可以支持大数据量的生成,项目中使用的poi是3.1的,上传的是4.1的。
用开源 Apache POI 技术导出Excel,解决导出大数据出现OOM、栈溢出问题,此资源可实现百万级数据多线程分批导出Excel文件,不会内存溢出,生产环境已很稳定的使用者,所以用到的技术很核心、值得参考
轻松解决普通poi形式导出Excel的中出现的栈溢出问题,此资源可实现千万级数据分批导出csv文件,csv大数据量导出(千万级别,不会内存溢出),多线程导出 ,生产环境已经很稳定的使用着
使用qt多线程,通过QAxObject将固定格式的文本文件(demo提供了选择原始文件,暂时使用的模拟数据),导出到excel,实现了进度显示
30万的数据量,生成多个excel最后打包成zip下载,是工程,直接导入就行
基于springboot和poi实现单线程和多线程导出Excel之单线程导出的代码。对于工作中导出Excel数据的小伙伴有一定的帮助作用。代码比较简单易学不需要太深的底层只是既可以使用,代码完全可以直接复制粘贴即可能在自己...
java解决大批量数据导出Excel产生内存溢出的方案
整合了导出DataTable到Excel的方法,可以实现导出到Web程序和Windows桌面程序对Excel文件的操作。 整合了多线程处理技术,针对海量数据的Excel导出,可以保证导出数据的操作流畅性,而不会导致假死等现象的...
阿里巴巴easyExcel实现大数据导出!!
海量数据导出Excel源码,用xml拼装Excel文件超过65525自动分sheet,经过实测,开发机器导出一千万数据40分钟
主要为大家详细介绍了java导出大批量即百万以上数据的excel文件,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
使用Excel相关的COM组件封装的报表打印功能,多线程方式导出报表,采用配置文件设置报表的相关信息,在Visual C++ 6.0下测试通过。
本篇文章主要介绍了C#实现几十万级数据导出Excel及Excel各种操作实例,这里整理了详细的代码,有需要的小伙伴可以参考下。
使用Excel相关的COM组件封装的报表打印功能,多线程方式导出报表,采用配置文件设置报表的相关信息,在Visual C++ 6.0下测试通过。 本版本重新构造了报表导出的参数结构信息,使用CExcelWnd封装了报表打印和导出的...
一般企业在使用报表过程中,经常要导出一些报表到excel文件,再通过web或ftp或文件共享的方式给其它用户下载. 软件的想法是将要下载的报表写好sql,再放入到LXL_SQLS_CSV表中,设定好下载路径,生成的文件地址等信息. ...
Warship+NPOI为一款基于NPOI的实体化Excel操作组件,包含丰富的组件化封装,全部基于实体化、对象化操作,不需要用户再对NPOI进行操作。...1)多线程 2)静态存储 3)委托 4)1万+ 条数据转换+校验: 1.3s 左右
该软件类似浏览器界面,快速多线程,可以导入导出Excel、HTML或ASCII文件。新增功能:按用户或扩展名分组搜索;保存为XML文档;XML文档对照等,为大家进行文件整理或者删除操作提供更为直观的参考。
7.包含了一个文件上传的功能,可上传单个或多个文件; 8.Excel导入导出工具使用EasyPOI来完成:https://easypoi.mydoc.io/ ,想导出为Excel直接在PO中使用@Excel注解 9、还支持自定义样式的模板导出 10、包含了登录...
一、TreeSize free官方版是一款硬盘空间管理工具,它能够显示文件大小和实际占空间数及其浪费的空间等,让用户可以最清楚的了解电脑... 4、该软件类似浏览器界面,快速多线程,可以导入导出Excel、HTML或ASCII文件。