title: Multithreading based on duplicated jOOλ streams
body: <p>The code below represents a toy example of the problem I am trying to solve.</p>
  
  <p>Imagine that we have an original stream of data <code>originalStream</code> and that the goal is to apply 2 very different data processing.  As an example here, one data processing will multiply each element by 2 and sum the result (<code>dataProcess1</code>) and the other will multiply by 4 and sum the result (<code>dataProcess2</code>).  Obviously the operation would not be so simple in real life....</p>
  
  <p>The idea is to use <code>jOOλ</code> in order to duplicate the stream and apply both operations to the 2 streams.  However, the trick is that I want to run both data processing in different threads.  Since <code>originalStream.duplicate()</code> is not thread-safe out of the box, the code below will fail to give the right result which should be: <em>result1 = 570; result2 = 180</em>.  Instead the code may unpredictably fail on NPE, yield the wrong result or (sometimes) even give the right result...</p>
  
  <p>The question is how to <strong>minimally</strong> modify the code such that it will become thread-safe.  </p>
  
  <p><strong>Note</strong> that I do not want to first collect the stream into a list and then generate 2 new streams.  Instead I want to stay with streams until they are eventually collected at the end of the data process.  It may not be the most efficient nor the most logical thing to want to do but I think it is nevertheless conceptually interesting.  <strong>Note also</strong> that I wish to keep using <code>org.jooq.lambda.Seq</code> (<em>group: 'org.jooq', name: 'jool', version: '0.9.12'</em>) as much as possible as the real data processing functions will use methods that are specific to this library and not present in regular Java streams.</p>
  
  <pre><code>Seq&lt;Long&gt; originalStream = seq(LongStream.range(0, 10));
  Tuple2&lt;Seq&lt;Long&gt;, Seq&lt;Long&gt;&gt; duplicatedOriginalStream = originalStream.duplicate();
  
  ExecutorService executor = Executors.newFixedThreadPool(2);
  List&lt;Future&lt;Long&gt;&gt; res = executor.invokeAll(Arrays.asList(
      () -&gt; duplicatedOriginalStream.v1.map(x -&gt; 2 * x).zipWithIndex().map(x -&gt; x.v1 * x.v2).reduce((x, y) -&gt; x + y).orElse(0L),
      () -&gt; duplicatedOriginalStream.v2.map(x -&gt; 4 * x).reduce((x, y) -&gt; x + y).orElse(0L)
  ));
  executor.shutdown();
  
  System.out.printf("result1 = %d\tresult2 = %d\n", res.get(0).get(), res.get(1).get());
  </code></pre>