@Override
    public <K, V, C extends Collection<V>, M extends Multimap<K, V, C>> M toMultimap(final Function<? super T, ? extends K> keyMapper,
            final Function<? super T, ? extends V> valueMapper, final Supplier<? extends M> mapFactory) {
        assertNotClosed();

        if (maxThreadNum <= 1 || toIndex - fromIndex <= 1) {
            return super.toMultimap(keyMapper, valueMapper, mapFactory);
        }

        // return collect(Collectors.toMultimap(keyMapper, valueMapper, mapFactory));

        //    final M res = mapFactory.get();
        //    final ConcurrentMap<K, List<U>> tmp = collect(Collectors.groupingByConcurrent(keyMapper, Collectors.mapping(valueMapper, Collectors.<U> toList())));
        //
        //    for (Map.Entry<K, List<U>> entry : tmp.entrySet()) {
        //        res.putAll(entry.getKey(), entry.getValue());
        //    }
        //
        //    return res;

        final int threadNum = N.min(maxThreadNum, (toIndex - fromIndex));
        final List<ContinuableFuture<M>> futureList = new ArrayList<>(threadNum);
        final Holder<Throwable> eHolder = new Holder<>();

        if (splitor == Splitor.ARRAY) {
            final int sliceSize = (toIndex - fromIndex) / threadNum + ((toIndex - fromIndex) % threadNum == 0 ? 0 : 1);

            for (int i = 0; i < threadNum; i++) {
                final int sliceIndex = i;

                futureList.add(asyncExecutor.execute(new Callable<M>() {
                    @Override
                    public M call() {
                        int cursor = fromIndex + sliceIndex * sliceSize;
                        final int to = toIndex - cursor > sliceSize ? cursor + sliceSize : toIndex;

                        M map = mapFactory.get();

                        try {
                            while (cursor < to && eHolder.value() == null) {
                                map.put(keyMapper.apply(elements[cursor]), valueMapper.apply(elements[cursor]));
                                cursor++;
                            }
                        } catch (Exception e) {
                            setError(eHolder, e);
                        }

                        return map;
                    }
                }));
            }
        } else {
            final MutableInt cursor = MutableInt.of(fromIndex);

            for (int i = 0; i < threadNum; i++) {
                futureList.add(asyncExecutor.execute(new Callable<M>() {

                    @Override
                    public M call() {
                        M map = mapFactory.get();
                        T next = null;

                        try {
                            while (eHolder.value() == null) {
                                synchronized (elements) {
                                    if (cursor.intValue() < toIndex) {
                                        next = elements[cursor.getAndIncrement()];
                                    } else {
                                        break;
                                    }
                                }

                                map.put(keyMapper.apply(next), valueMapper.apply(next));
                            }
                        } catch (Exception e) {
                            setError(eHolder, e);
                        }

                        return map;
                    }
                }));
            }
        }

        if (eHolder.value() != null) {
            close();
            throw N.toRuntimeException(eHolder.value());
        }

        M res = null;

        try {
            for (ContinuableFuture<M> future : futureList) {
                if (res == null) {
                    res = future.get();
                } else {
                    final M m = future.get();

                    for (Map.Entry<K, C> entry : m.entrySet()) {
                        res.putAll(entry.getKey(), entry.getValue());
                    }
                }
            }
        } catch (InterruptedException | ExecutionException e) {
            throw N.toRuntimeException(e);
        } finally {
            close();
        }

        return res;
    }
@ Override public < K , V , C extends Collection < V > , M extends Multimap < K , V , C > > M toMultimap ( final Function < ? super T , ? extends K > keyMapper , final Function < ? super T , ? extends V > valueMapper , final Supplier < ? extends M > mapFactory ) { assertNotClosed ( ) ; if ( maxThreadNum <= 1 || toIndex - fromIndex <= 1 ) { return super . toMultimap ( keyMapper , valueMapper , mapFactory ) ; } final int threadNum = N . min ( maxThreadNum , ( toIndex - fromIndex ) ) ; final List < ContinuableFuture < M > > futureList = new ArrayList < > ( threadNum ) ; final Holder < Throwable > eHolder = new Holder < > ( ) ; if ( splitor == Splitor . ARRAY ) { final int sliceSize = ( toIndex - fromIndex ) / threadNum + ( ( toIndex - fromIndex ) % threadNum == 0 ? 0 : 1 ) ; for ( int i = 0 ; i < threadNum ; i ++ ) { final int sliceIndex = i ; futureList . add ( asyncExecutor . execute ( new Callable < M > ( ) { @ Override public M call ( ) { int cursor = fromIndex + sliceIndex * sliceSize ; final int to = toIndex - cursor > sliceSize ? cursor + sliceSize : toIndex ; M map = mapFactory . get ( ) ; try { while ( cursor < to && eHolder . value ( ) == null ) { map . put ( keyMapper . apply ( elements [ cursor ] ) , valueMapper . apply ( elements [ cursor ] ) ) ; cursor ++ ; } } catch ( Exception e ) { setError ( eHolder , e ) ; } return map ; } } ) ) ; } } else { final MutableInt cursor = MutableInt . of ( fromIndex ) ; for ( int i = 0 ; i < threadNum ; i ++ ) { futureList . add ( asyncExecutor . execute ( new Callable < M > ( ) { @ Override public M call ( ) { M map = mapFactory . get ( ) ; T next = null ; try { while ( eHolder . value ( ) == null ) { synchronized ( elements ) { if ( cursor . intValue ( ) < toIndex ) { next = elements [ cursor . getAndIncrement ( ) ] ; } else { break ; } } map . put ( keyMapper . apply ( next ) , valueMapper . apply ( next ) ) ; } } catch ( Exception e ) { setError ( eHolder , e ) ; } return map ; } } ) ) ; } } if ( eHolder . value ( ) != null ) { close ( ) ; throw N . toRuntimeException ( eHolder . value ( ) ) ; } M res = null ; try { for ( ContinuableFuture < M > future : futureList ) { if ( res == null ) { res = future . get ( ) ; } else { final M m = future . get ( ) ; for ( Map . Entry < K , C > entry : m . entrySet ( ) ) { res . putAll ( entry . getKey ( ) , entry . getValue ( ) ) ; } } } } catch ( InterruptedException | ExecutionException e ) { throw N . toRuntimeException ( e ) ; } finally { close ( ) ; } return res ; }
}