title: POI single vs multithreaded performance
body: <p>I have a pretty simple use case - read an Excel spreadsheet with POI, populate some values, run cell updates and retrieve calculation outputs.</p>
  <p>What puzzles me is performance. If I run single-threaded, Excel file takes a few seconds to get loaded/parsed, but for each subsequent request processing time decreases. If I run exactly the task via multiple threads and then join, the performance is actually 10 times slower on all threads. Where am I messing up?</p>
  <p>Here is the test output:</p>
  <pre><code>Running Multi Threaded
  Thread Thread-8 finished run 7092
  Thread Thread-9 finished run 7092
  Thread Thread-7 finished run 7092
  Thread Thread-10 finished run 7092
  Thread Thread-4 finished run 7092
  Thread Thread-5 finished run 7092
  Thread Thread-3 finished run 7107
  Thread Thread-2 finished run 7107
  Thread Thread-6 finished run 7107
  Thread Thread-1 finished run 7108
  Finished in 7113
  
  Running Single Threaded
  Thread Thread-11 finished run 591
  Thread Thread-12 finished run 192
  Thread Thread-13 finished run 173
  Thread Thread-14 finished run 149
  Thread Thread-15 finished run 126
  Thread Thread-16 finished run 133
  Thread Thread-17 finished run 159
  Thread Thread-18 finished run 124
  Thread Thread-19 finished run 131
  Thread Thread-20 finished run 121
  Finished in 1907
  Process finished with exit code 0
  </code></pre>
  <p>Here is the test:</p>
  <pre><code>package com.test;
  
  import org.apache.poi.xssf.usermodel.XSSFWorkbook;
  import org.junit.jupiter.api.Test;
  
  import java.io.BufferedInputStream;
  import java.io.FileInputStream;
  import java.util.ArrayList;
  import java.util.List;
  import java.util.Map;
  
  public class PerfTest {
  
      @Test
      public void runSingleThreaded() throws Exception {
          System.out.println(&quot;Running Single Threaded&quot;);
  
          long start = System.currentTimeMillis();
          for (int i = 0; i &lt; 10; i++) {
              new PoiThread().run();
          }
          System.out.println(&quot;Finished in &quot; + (System.currentTimeMillis() - start));
      }
  
      @Test
      public void runMultiThreaded() throws Throwable {
          System.out.println(&quot;Running Multi Threaded&quot;);
  
          List&lt;Thread&gt; threads = new ArrayList&lt;&gt;();
          for (int i = 0; i &lt; 10; i++) {
              threads.add(new PoiThread());
          }
  
          long start = System.currentTimeMillis();
          threads.forEach(t -&gt; t.start());
          threads.forEach(t -&gt; {
              try {
                  t.join();
              } catch (InterruptedException e) {
                  e.printStackTrace();
              }
          });
          System.out.println(&quot;Finished in &quot; + (System.currentTimeMillis() - start));
      }
  
      public static class PoiThread extends Thread {
  
          @Override
          public void run() {
              try {
                  long runStart = System.currentTimeMillis();
                  XSSFWorkbook workbook = new XSSFWorkbook(new BufferedInputStream(new FileInputStream(&quot;src/main/resources/customer.xlsx&quot;)));
                  Helper helper = new Helper(workbook, &quot;test&quot;, workbook.getCreationHelper().createFormulaEvaluator());
                  String ref = helper.getFieldValueCellReference(&quot;Inputs&quot;, &quot;customer&quot;);
                  helper.evaluateAllCells();
                  Map&lt;String, Double&gt; premiums = helper.getAllNumericFields(&quot;Premium Outputs&quot;);
                  System.out.println(String.format(&quot;Thread %s finished run %s&quot;, this.getName(), (System.currentTimeMillis() - runStart)));
              } catch (Exception e) {
                  e.printStackTrace();
              }
          }
  
      }
  
  }
  </code></pre>