多线程调用Excel导出方法时遭遇java.lang.InterruptedException问题求助
解决多线程导出加密Excel时的InterruptedException问题
首先,InterruptedException一般是线程在阻塞状态(比如IO等待、资源获取等待)时被中断导致的。结合你的代码,主要问题集中在资源未正确释放、线程安全隐患和异常处理不规范上,下面一步步分析并给出修复方案:
一、核心问题拆解
- 资源未统一回收:Connection、Statement、ResultSet、SXSSFWorkbook以及各类IO流只在try块中关闭,一旦中途抛出异常就会跳过关闭逻辑,多线程下会造成资源泄漏,引发线程阻塞甚至被中断。
- SXSSFWorkbook临时文件未清理:SXSSFWorkbook会生成临时文件存储超出内存的行数据,不调用
dispose()会导致临时文件堆积,占用系统资源,触发线程中断。 - 中断状态丢失:捕获
InterruptedException后没有恢复线程的中断标记,导致后续逻辑无法感知线程被中断的状态。 - 加密阶段IO操作存在阻塞风险:文件写入和加密操作未确保流完全关闭,多线程下IO资源竞争可能导致线程长时间阻塞被中断。
二、修复后的完整代码
public void exportTOExcel(ExportReport exportReport) { Connection connection = null; ResultSet rs = null; Statement statement = null; SXSSFWorkbook wb = null; FileOutputStream out = null; POIFSFileSystem fs = null; OPCPackage opc = null; FileOutputStream fos = null; try { // 生成唯一文件名(毫秒级时间戳确保多线程下无重复) String fileName = exportReport.getReportName() + "_" + new SimpleDateFormat("MMM_dd_yyyy_HH_mm_ss_SSS").format(Calendar.getInstance().getTime()); String sheetName = exportReport.getReportName(); String excelFile = PropertyLoader.FILE_DOWNLOAD_PATH + "\\" + fileName + ".xlsx"; // 数据库连接与查询 connection = DatabaseConnection.openDBConnection(); statement = connection.createStatement(); rs = statement.executeQuery(exportReport.getQuery()); // 创建SXSSFWorkbook并配置单元格样式 wb = new SXSSFWorkbook(100); Sheet workSheet = wb.createSheet(sheetName); DataFormat fmt = wb.createDataFormat(); CellStyle cellStyle = wb.createCellStyle(); cellStyle.setDataFormat(fmt.getFormat("@")); // 写入数据库结果到Excel int rowNumber = 1; ResultSetMetaData metaData = rs.getMetaData(); int columnCount = metaData.getColumnCount(); while (rs.next()) { Row row = workSheet.createRow(rowNumber); for (int i = 1; i <= columnCount; i++) { Object obj = rs.getObject(i); String value = obj != null ? String.valueOf(obj) : ""; Cell cell = row.createCell(i - 1); cell.setCellStyle(cellStyle); cell.setCellValue(value); } rowNumber++; } // 自动调整列宽 for (int i = 0; i < columnCount; i++) { workSheet.autoSizeColumn(i); } // 写入未加密Excel文件 out = new FileOutputStream(excelFile); wb.write(out); // 对Excel文件进行加密处理 fs = new POIFSFileSystem(); EncryptionInfo info = new EncryptionInfo(fs, EncryptionMode.agile); Encryptor enc = info.getEncryptor(); enc.confirmPassword(exportReport.getPassword()); opc = OPCPackage.open(excelFile, PackageAccess.READ_WRITE); OutputStream os = enc.getDataStream(fs); opc.save(os); fos = new FileOutputStream(excelFile); fs.writeFilesystem(fos); } catch (InterruptedException e) { // 恢复线程中断状态,让上层逻辑能感知到中断事件 Thread.currentThread().interrupt(); e.printStackTrace(); } catch (Exception e) { e.printStackTrace(); } finally { // 统一关闭所有资源,彻底避免资源泄漏 try { if (fos != null) fos.close(); if (opc != null) opc.close(); if (fs != null) fs.close(); if (out != null) out.close(); // 清理SXSSFWorkbook生成的临时文件 if (wb != null) wb.dispose(); if (rs != null) rs.close(); if (statement != null) statement.close(); if (connection != null) connection.close(); } catch (Exception e) { e.printStackTrace(); } } }
三、额外优化建议
- 替换线程不安全的日期格式化:
SimpleDateFormat是非线程安全的,多线程下可能出现日期格式错误,建议改用Java 8+的DateTimeFormatter:DateTimeFormatter formatter = DateTimeFormatter.ofPattern("MMM_dd_yyyy_HH_mm_ss_SSS"); String fileName = exportReport.getReportName() + "_" + formatter.format(LocalDateTime.now()); - 使用try-with-resources简化代码:Java 7+支持自动关闭资源的语法,能进一步确保资源释放,简化代码结构:
try (Connection connection = DatabaseConnection.openDBConnection(); Statement statement = connection.createStatement(); ResultSet rs = statement.executeQuery(exportReport.getQuery())) { // 核心业务逻辑 } catch (Exception e) { // 异常处理 } - 添加超时控制:对数据库查询、文件IO操作添加超时设置,防止线程因长时间阻塞被中断。
内容的提问来源于stack exchange,提问作者Aditya




