将三个list往一个excel表的三个sheet中写入,能用多线程提高写入速度

1. 多线程大批量写入可能导致 OOM

多线程可以加速写入操作,因为每个线程可以独立处理一个 Sheet。

但多线程会导致内存占用增加,因为多个线程可能同时将数据加载到内存中。

如果每个 List 数据量过大,而 JVM 的堆内存不够,就会触发 OOM。

2. 解决 OOM 问题的策略

为了保证程序稳定性并避免 OOM,采取以下措施:

1,使用分批处理数据 :将大的 List 分批写入,避免一次性加载所有数据到内存中。
2,使用 SXSSFWorkbook 流式写入 :它是 Apache POI 提供的专门用于大数据量 Excel 操作的类。
3,合理设置 JVM 堆内存 :通过 JVM 参数如 -Xmx2G 提高堆内存限制。
4,多线程写入:每个线程负责一个 Sheet,实现并发写入加速。

3. 代码示例

假设有三个大 List,我们分别写入 Excel 的三个 Sheet:

依赖引入

使用 Apache POI,需要添加以下依赖(Maven):

java 复制代码
<dependency>
    <groupId>org.apache.poi</groupId>
    <artifactId>poi-ooxml</artifactId>
    <version>5.2.3</version>
</dependency>
代码实现
java 复制代码
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.streaming.SXSSFWorkbook;

import java.io.FileOutputStream;
import java.io.IOException;
import java.util.*;
import java.util.concurrent.*;

public class MultiThreadExcelWriter {

    // 方法:分批写入数据到 Sheet
    private static void writeDataToSheet(Sheet sheet, List<String> data, int batchSize) {
        int rowIndex = 0;
        for (int i = 0; i < data.size(); i += batchSize) {
            List<String> batch = data.subList(i, Math.min(i + batchSize, data.size()));
            for (String item : batch) {
                Row row = sheet.createRow(rowIndex++);
                Cell cell = row.createCell(0);
                cell.setCellValue(item);
            }
        }
    }

    public static void main(String[] args) {
        // 假设有三个大 List
        final List<String> list1 = generateLargeList(1000000); // 模拟100万条数据
        final List<String> list2 = generateLargeList(1000000);
        final List<String> list3 = generateLargeList(1000000);

        // 创建线程池,控制并发线程数
        ExecutorService executor = Executors.newFixedThreadPool(3);

        // 使用 SXSSFWorkbook 实现流式写入
        Workbook workbook = new SXSSFWorkbook();

        // 定义任务
        List<Callable<Void>> tasks = new ArrayList<>();

        tasks.add(() -> {
            Sheet sheet1 = workbook.createSheet("Sheet1");
            writeDataToSheet(sheet1, list1, 10000); // 分批写入,每批1万条
            return null;
        });

        tasks.add(() -> {
            Sheet sheet2 = workbook.createSheet("Sheet2");
            writeDataToSheet(sheet2, list2, 10000);
            return null;
        });

        tasks.add(() -> {
            Sheet sheet3 = workbook.createSheet("Sheet3");
            writeDataToSheet(sheet3, list3, 10000);
            return null;
        });

        try {
            // 执行任务
            executor.invokeAll(tasks);

            // 将数据写入 Excel 文件
            try (FileOutputStream fos = new FileOutputStream("output.xlsx")) {
                workbook.write(fos);
            }
            System.out.println("Excel 文件写入完成!");

        } catch (InterruptedException | IOException e) {
            e.printStackTrace();
        } finally {
            // 关闭线程池和资源
            executor.shutdown();
            try {
                workbook.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    // 模拟生成大数据 List
    private static List<String> generateLargeList(int size) {
        List<String> list = new ArrayList<>(size);
        for (int i = 0; i < size; i++) {
            list.add("Data-" + i);
        }
        return list;
    }
}

4. 代码说明

多线程处理:

使用 ExecutorService 创建固定大小的线程池(3个线程)。

每个线程负责一个 Sheet,并将数据分批写入。
分批写入:

writeDataToSheet 方法中,通过 subList 将数据分成小批次(例如每批 10,000 条)写入。

这样可以避免一次性加载过多数据到内存。
流式写入:

使用 SXSSFWorkbook 代替传统的 XSSFWorkbook,它支持流式写入并限制内存占用。
堆内存设置:

在运行程序时,通过 JVM 参数增加堆内存:

java 复制代码
java -Xmx2G -jar yourprogram.jar

这里 -Xmx2G 表示将最大堆内存设置为 2GB

5. 执行结果

Excel 文件生成速度更快,因为三个线程并发写入三个 Sheet。

内存占用更可控,通过分批写入和流式写入避免一次性加载过多数据。

Sheet 顺序:

多线程写入不会改变 Sheet 的顺序,因为 SXSSFWorkbook.createSheet 是线程安全的,并且会按照代码中调用顺序创建 Sheet。

相关推荐
好好研究1 小时前
学习栈和队列的插入和删除操作
数据结构·学习
挺菜的4 小时前
【算法刷题记录(简单题)003】统计大写字母个数(java代码实现)
java·数据结构·算法
2401_858286115 小时前
125.【C语言】数据结构之归并排序递归解法
c语言·开发语言·数据结构·算法·排序算法·归并排序
双叶8366 小时前
(C++)学生管理系统(正式版)(map数组的应用)(string应用)(引用)(文件储存的应用)(C++教学)(C++项目)
c语言·开发语言·数据结构·c++
学不动CV了8 小时前
数据结构---链表结构体、指针深入理解(三)
c语言·arm开发·数据结构·stm32·单片机·链表
全干engineer9 小时前
Spring Boot 实现主表+明细表 Excel 导出(EasyPOI 实战)
java·spring boot·后端·excel·easypoi·excel导出
Fireworkitte9 小时前
Java 中导出包含多个 Sheet 的 Excel 文件
java·开发语言·excel
算法_小学生10 小时前
LeetCode 287. 寻找重复数(不修改数组 + O(1) 空间)
数据结构·算法·leetcode
Wo3Shi4七13 小时前
哈希冲突
数据结构·算法·go
V我五十买鸡腿14 小时前
顺序栈和链式栈
c语言·数据结构·笔记·算法