code: public static <T, R> ComposableFuture<List<R>> batchUnordered(final List<T> elements, final int parallelism,
                                                                  final FutureSuccessHandler<T, R> producer) {
      Preconditions.checkArgument(parallelism > 0, "Parallelism must be > 0, not %s", parallelism);
  
      final AtomicIntegerArray nodesState = new AtomicIntegerArray(elements.size());
  
      @SuppressWarnings("unchecked") final R[] results = (R[]) new Object[elements.size()];
  
      final AtomicInteger pendingNodeLowerBound = new AtomicInteger(parallelism + 1);
      final List<ComposableFuture<Void>> futures = new ArrayList<>(parallelism);
      for (int rootNode = 1; rootNode <= parallelism; rootNode++) {
        futures.add(processTree(elements, rootNode, nodesState, results, pendingNodeLowerBound, producer, true));
      }
  
      return ComposableFutures.all(true, futures).map(__ -> Arrays.asList(results));
    }
docs: Execute the producer on each element in the list in parallel.
  Each parallel flow will opportunistically try to process
  The next available item on the list upon completion of the previous one.
  Use this method when execution time for each element is highly irregular so that slow elements
  In the beginning of the list won't necessarily hold back the rest of the execution.
  <p>
  An error in one of the futures produced by the producer will end the flow and return a future containing the error
  
  @param elements    the input to the producer
  @param parallelism how many items will be processed in parallel
  @param producer    produces a future based on input from the element list
  @param <T>         the type of the elements in the input list
  @param <R>         the result type of the future returning from the producer
  @return a future containing a list of all the results produced by the producer.