java 用线程异步导出excel 您所在的位置:网站首页 java中导出海量数据到excel java 用线程异步导出excel

java 用线程异步导出excel

2023-07-14 05:53| 来源: 网络整理| 查看: 265

一、前言

现在用的比较多的都是用POI技术来导出Excel,对于导出数据量不大的直接用POI技术按部就班实现即可,但是对于数据量大且需要导出的数据封装业务较复杂,单纯的用POI技术实现在高并发导出数据量较大时就会出现应用程序内存溢出,为了解决此问题,以下通过用线程池异步导出的方式实现。

二、线程池

从Java线程池ThreadPoolExecutor提供了四个构造方法中了解到,在如下场景的的时候,就需要我们使用自定ThreadPoolExecutor和BlockingQueue队列结合使用来处理。

1、需要的子线程数量很多,但是数量不确定。 2、子线程有自己的优先级,根据优先级来确定执行的先后顺序。 3、监听线程池的开始,结束,关闭等状态。 ThreadPoolExecutor构造方法之四如下:

//使用给定的初始参数创建一个新的ThreadPoolExecutor public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue workQueue, ThreadFactory threadFactory, RejectedExecutionHandler handler)

主要参数

corePoolSize:核心线程数

       核心线程会一直存活,及时没有任务需要执行。当线程数小于核心线程数时,即使有线程空闲,线程池也会优先创建新线程处理。

maxPoolSize:最大线程数

       当线程数>=corePoolSize,且任务队列已满时。线程池会创建新线程来处理任务。        当线程数=maxPoolSize,且任务队列已满时,线程池会拒绝处理任务而抛出异常。

keepAliveTime:非核心线程闲置时的超时时长

       超过这个时长,非核心线程就会被回收。当ThreadPoolExecutor的allowCoreThreadTimeOut属性设置为true 时,keepAliveTime 同样        会作用于核心线程。

unit:用于指定 keepAliveTime 参数的时间单位

       常用的有 TimeUnit .MILLISECONDS 和 TimeUnit .SECONDS。

workQueue:线程池中的任务队列

       通过线程池的 execute 方法提交的 Runnable 对象会存储在这个参数中。

threadFactory:线程工厂

       为线程池提供创建新的线程的功能。threadFactory 是一个接口,它只有一个方法: public abstract Thread newThread (Runnable r);

RejectedExecutionHandler:通常叫做拒绝策略

       在线程池已经关闭的情况下或者当线程数已经达到maxPoolSize且队列已满。只要满足其中一种时,在使用execute() 来提交新的任务         时将会拒绝,而默认的拒绝策略是抛一个 RejectedExecutionException 异常。

三、执行说明

提交一个新任务到线程池时首先线程池判断基本线程池(corePoolSize)是否已满?没满,创建一个工作线程来执行任务。满了,则进入下个流程;其次线程池判断工作队列(workQueue)是否已满?没满,则将新提交的任务存储在工作队列里。满了,则进入下个流程;最后线程池判断整个线程池(maximumPoolSize)是否已满?没满,则创建一个新的工作线程来执行任务,满了,则交给饱和策略来处理这个任务;如果线程池中的线程数量大于 corePoolSize 时,如果某线程空闲时间超过keepAliveTime,线程将被终止,直至线程池中的线程数目不大于corePoolSize;如果允许为核心池中的线程设置存活时间,那么核心池中的线程空闲时间超过 keepAliveTime,线程也会被终止。

四、关键程序代码 public void createThreadExcel(final Vo vo, final Long exportExcelId,final String fileName,final NosCurrentUser userInfo) { Runnable runnable = new Runnable(){ @Override public void run() { //具体的业务(用分页查询出数据,先生成EXCEL文件,再保存到文件服务端且生成一个文件路径,前端直接下载) ExportExcel exportExcel = createExcel(vo,fileName,userInfo); }}; //注意:使用单例模式 ExportQueuePoolService.getInstance().put(runnable); } package cn.uce.nos.common.util.threadPool; public class ExportQueuePoolService{ BlockThreadPool pool=null; private ThreadCounter() { pool = new BlockThreadPool(3); } public static ExportQueuePoolServiceinstance = null; public static ExportQueuePoolServicegetInstance() { if (instance == null) { synchronized (ExportQueuePoolService.class) { if (instance == null) { instance = new ExportQueuePoolService(); } } } return instance; } public void put(Runnable service){ pool.execute(service); } } package cn.uce.nos.common.util.threadPool; import java.util.concurrent.ArrayBlockingQueue; import java.util.concurrent.RejectedExecutionHandler; import java.util.concurrent.ThreadFactory; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; public class BlockThreadPool { private ThreadPoolExecutor pool = null; public BlockThreadPool(int poolSize) { pool = new ThreadPoolExecutor(poolSize, 2, 0, TimeUnit.MILLISECONDS, new ArrayBlockingQueue(80), new CustomThreadFactory(), new CustomRejectedExecutionHandler()); } public void destory() { if (pool != null) { pool.shutdownNow(); } } private class CustomThreadFactory implements ThreadFactory { private AtomicInteger count = new AtomicInteger(0); @Override public Thread newThread(Runnable r) { Thread t = new Thread(r); String threadName = BlockThreadPool.class.getSimpleName() + count.addAndGet(1); t.setName(threadName); return t; } } private class CustomRejectedExecutionHandler implements RejectedExecutionHandler { @Override public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) { try { // 核心改造点,由blockingqueue的offer改成put阻塞方法 System.out.println("r-size-befor===="+executor.getQueue().size()); executor.getQueue().put(r); System.out.println("r-size-end===="+executor.getQueue().size()); } catch (InterruptedException e) { e.printStackTrace(); } } } public void execute(Runnable runnable) { this.pool.execute(runnable); } } 五、引用相关文章

1、Java并发ThreadPoolExecutor+BlockingQueue使用详解

2、线程池之ThreadPoolExecutor使用

 

 



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有