EasyExcel 多线程导出
时间: 2025-01-05 20:27:41 浏览: 93
### 如何使用 EasyExcel 实现多线程导出 Excel 文件
为了处理大数据量的报表导出并提高效率,可以采用多线程的方式进行数据导出。下面是一个具体的实现方案。
#### 创建自定义的数据读取器类 `DataReader`
此部分负责从数据库或其他源获取待导出的数据:
```java
public class DemoDataReader implements DataReader<DemoData> {
private List<DemoData> dataList;
@Override
public boolean hasNext() {
return !dataList.isEmpty();
}
@Override
public DemoData next() throws Exception {
if (hasNext()) {
return dataList.remove(0);
}
throw new NoSuchElementException("No more elements");
}
// 构造函数用于初始化数据列表
public DemoDataReader(List<DemoData> dataList) {
this.dataList = dataList;
}
}
```
#### 定义数据模型类 `DemoData`
该实体类表示要被写入到 Excel 中的一条记录结构:
```java
@Data
class DemoData {
String string;
Integer integer;
Date date;
// Getters and Setters...
}
```
#### 编写自定义的数据写出器类 `DataWriter`
此类实现了将每一条数据实际写入文件的功能:
```java
public class DemoDataWriter extends AbstractExcelWriteHandler {
@Override
protected void invokeInternal(WriteSheetHolder writeSheetHolder,
AnalysisContext context,
WriteTableHolder writeTableHolder) {
Sheet sheet = writeSheetHolder.getSheet();
// 可在此处设置样式等操作
super.invokeInternal(writeSheetHolder, context, writeTableHolder);
}
}
```
#### 多线程分页导出逻辑封装于 `ExcelExport` 类中
这个核心组件协调着整个过程中的并发控制与资源管理:
```java
import com.alibaba.excel.write.handler.AbstractExcelWriteHandler;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
public class ExcelExport<T> {
private final ThreadPoolTaskExecutor threadPool;
private final int pageSize;
private final DataReader<T> dataReader;
private final DataWriter<T> dataWriter;
public ExcelExport(DataReader<T> dataReader, DataWriter<T> dataWriter) {
this(dataReader, dataWriter, Runtime.getRuntime().availableProcessors());
}
public ExcelExport(DataReader<T> dataReader, DataWriter<T> dataWriter, int poolSize) {
this.dataReader = dataReader;
this.dataWriter = dataWriter;
this.pageSize = 10_000; // 默认页面大小为一万条记录
this.threadPool = createThreadPool(poolSize);
}
/**
* 开始执行多线程分页导出流程.
*/
public void export(int startPage, long totalRecords) throws InterruptedException, ExecutionException {
int totalPages = calculateTotalPages(totalRecords);
Future<?>[] futures = new Future[totalPages];
for (int i = 0; i < totalPages; ++i) {
int currentPageIndex = i + startPage;
Callable<Void> task = () -> processPage(currentPageIndex);
futures[i] = threadPool.submit(task);
}
waitForAllTasksToComplete(futures);
closeResources();
}
private void processPage(int pageIndex) {
try {
List<T> pageItems = fetchPage(pageIndex);
synchronized (dataWriter) {
dataWriter.writeBatch(pageItems.toArray(new Object[0]));
}
} catch (Exception e) {
System.err.println("Failed to process page " + pageIndex + ": " + e.getMessage());
}
}
private List<T> fetchPage(int pageIndex) throws Exception {
List<T> result = new ArrayList<>();
for (int j = 0; j < pageSize && dataReader.hasNext(); ++j) {
T item = dataReader.next();
result.add(item);
}
return result;
}
private static ThreadPoolTaskExecutor createThreadPool(int corePoolSize) {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(corePoolSize);
executor.setMaxPoolSize(Integer.MAX_VALUE);
executor.initialize();
return executor;
}
private static int calculateTotalPages(long recordCount) {
return Math.toIntExact((recordCount + PAGE_SIZE - 1L) / PAGE_SIZE);
}
private static void waitForAllTasksToComplete(Future<?>... tasks) throws InterruptedException, ExecutionException {
for (Future<?> future : tasks) {
future.get();
}
}
private void closeResources() {
threadPool.shutdown();
}
}
```
通过上述代码片段展示了如何利用 Java 的多线程机制配合 EasyExcel 库来高效完成大量数据向 Excel 表格内的转换工作[^3]。
阅读全文
相关推荐

















