【Java】多线程操作Excel表格

利用Java读取Excel表格中的数据,并有相关的写操作。如果Excel表格数据量较多,单纯的读写十分耗时,但利用多线程的合理搭配可以节省不少时间。

以下就叙述在Java中如何使用多线程操作Excel表格。

  • 在Java中读取Excel表格推荐使用Poi类库,它支持Excel 2003Excel 2007+

    Maven的依赖配置如下:

    1
    2
    3
    4
    5
    <dependency>
    <groupId>org.apache.poi</groupId>
    <artifactId>poi-ooxml</artifactId>
    <version>3.17</version>
    </dependency>

    安装完依赖后,在程序中读取Excel表格十分便捷,如下所示:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    // 将文件读取至文件流中
    InputStream in = new FileInputStream(filePath);
    // 在从文件流中创建一个工作簿,以后对Excel的相关操作从该工作簿中进行
    Workbook wb = WorkbookFactory.create(in);
    // 读取第一个表格
    Sheet sheet = wb.getSheetAt(0);
    ...
    // 将操作完成后的工作簿导出
    OutputStream out = new FileOutputStream(savePath);
    wb.write(out)
    out.close();

    上面的读取Excel使用WorkbookFactory.create(in)来进行,无需担心Excel的版本问题,它已经在代码中自行做了判断。

  • 多线程的实现我主要使用CountdownLatchCachedTheadPool这两个类。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    protected static class PoiWrite implements Runnable {
    private final CountDownLatch latch;
    private Sheet sheet;
    private int start;
    private int end;
    public PoiWrite(CountDownLatch latch, Sheet sheet, int start, int end) {
    this.latch = latch;
    this.sheet = sheet;
    this.start = start;
    this.end = end;
    }
    @Override
    public void run() {
    try {
    // 这里操作Excel表格
    ...
    } catch (Exception e) {
    e.printStackTrace();
    } finally {
    // 该方法一定要放在finally中执行,确保计数器的减少
    latch.countDown();
    }
    }
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    public static void multiThreadReadExcel(String path) {
    // 使用线程池进行线程管理
    ExecutorService es = Executors.newCachedThreadPool();
    // 使用计数栅栏
    CountDownLatch latch = new CountDownLatch(4);
    InputStream in = null;
    Workbook wb = null;
    Sheet sheet = null;
    try {
    in = new FileInputStream(path);
    // 兼容Excel 2003和Excel 2007+
    wb = WorkbookFactory.create(in);
    sheet = wb.getSheetAt(0);
    es.submit(new PoiWrite(latch, sheet, 1, 500));
    es.submit(new PoiWrite(latch, sheet, 501, 1000));
    es.submit(new PoiWrite(latch, sheet, 1001, 1500));
    es.submit(new PoiWrite(latch, sheet, 1501, 2000));
    // 阻塞直至所有线程完成操作
    latch.await();
    es.shutdown();
    // 判断Excel的版本
    String file = null;
    if (path.endsWith(".xls")) {
    file = "./temp.xls";
    } else {
    file = "./temp.xlsx";
    }
    OutputStream out = new FileOutputStream(file);
    wb.write(out);
    out.close();
    } catch (Exception e) {
    e.printStackTrace();
    }
    }

我做过一个简单的记录,读写Excel表格中的2000条数据,不使用多线程和开几条线程的具体结果如下所示:

  • 不使用多线程执行完任务耗时141秒。
  • 开3个线程执行完任务耗时71秒。
  • 开4个线程执行完任务耗时53秒。
  • 开5个线程执行完任务耗时74秒。

因而操作Excel表格的时候,开启的线程数量不是越多越好,而是依靠你所使用的电脑的CPU核数所决定的。

开启的线程数量最好是你所使用的电脑的CPU核数的两倍,如我使用的笔记本为双核,则最好开4个线程。