自定义线程池+异步编排实现数据导出

文章展示了如何在Java中使用EasyExcel库进行异步Excel文件导出,配置了基于CPU核心数的线程池,并对可能出现的`CannotcallsendError()aftertheresponsehasbeencommitted`异常进行了分析,该异常源于多次响应同一个HTTP请求。

依赖

     <!-- easyexcel -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>easyexcel</artifactId>
            <version>3.2.1</version>
        </dependency>

线程池

private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors();
    private final Integer corePoolSize =Math.max(2, Math.min(CPU_COUNT - 1, 4));

    private final Integer maxPoolSize = CPU_COUNT * 2 + 1;

    private static final Integer KEEP_ALIVE_TIME = 30;


    @Bean(name = "asyncExecutor")
    @Primary
    public ThreadPoolTaskExecutor asyncServiceExecutor() {
   
   
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        //配置核心线程数
        executor.setCorePoolSize(corePoolSize);
        //配置最大线程数
        executor.setMaxPoolSize(maxPoolSize);
        //配置队列大小
        int queueCapacity = 1000;
        executor.setQueueCapacity(queueCapacity);
        executor.setKeepAliveSeconds(KEEP_ALIVE_TIME);
        //配置线程池中的线程的名称前缀
        executor.setThreadNamePrefix("asyncExecutor-");
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy())
@GetMapping("/exportLargeData") public void exportLargeData(){ log.info("开始导出数据!"); long startTime = System.currentTimeMillis(); try { String fileName = URLEncoder.encode("testList.xlsx", "UTF-8"); response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"); response.setHeader("Content-Disposition", "attachment;filename=" + fileName); ExportParams exportParams = new ExportParams(null, "测试导出", ExcelType.XSSF); // todo 如果后期数据超过50000条,但是想一次性全部导出,可结合POI,每查询1000条就写出,减少内存压力, // 但是导出效率可能受到影响 List<TestAccountExportDto> allData = new ArrayList<>(); AtomicInteger currentPage = new AtomicInteger(1); Page<TestAccountEntity> resultPage = null; // 单次导出限制只能导出50页数据,每页1000条数据,总数不超过50000条 for (int pageNum = currentPage.get(); pageNum <= 50 && (resultPage == null || resultPage.hasNext()); pageNum = currentPage.incrementAndGet()) { Page<TestAccountEntity> page = new Page<>(pageNum, 1000); resultPage = testAccountService.page(page); List<TestAccountExportDto> dataList = JsonUtil.getJsonToList( resultPage.getRecords(), TestAccountExportDto.class ); allData.addAll(dataList); log.info("总集合条数:{},当前页数:{}", allData.size(), pageNum); } try (Workbook workbook = ExcelExportUtil.exportExcel(exportParams, TestAccountExportDto.class, allData); OutputStream outputStream = response.getOutputStream()){ workbook.write(outputStream); outputStream.flush(); } long costTime = System.currentTimeMillis() - startTime; log.info("导出结束, 共耗费: {}", costTime); } catch (Exception e) { log.error("导出异常", e); throw new RuntimeException("导出异常"); } } 使用多线程优化上述导出功能的效率,考虑线程的异步编排数据库的最大连接为4,线程池的核心线程数也为4
06-09
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

缘不易

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值