com.pivovarit.collectors.AsyncOrderedParallelCollector Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of parallel-collectors Show documentation
Show all versions of parallel-collectors Show documentation
Parallel collection processing with customizable thread pools
package com.pivovarit.collectors;
import java.util.AbstractMap;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Comparator;
import java.util.List;
import java.util.Map.Entry;
import java.util.Set;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Executor;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.BiConsumer;
import java.util.function.Function;
import java.util.function.Supplier;
import java.util.stream.Collector;
import java.util.stream.Collectors;
import static java.util.Collections.emptySet;
import static java.util.Collections.synchronizedList;
import static java.util.concurrent.CompletableFuture.completedFuture;
/**
* @author Grzegorz Piwowarek
*/
final class AsyncOrderedParallelCollector>
extends AbstractParallelCollector, CompletableFuture>
implements AutoCloseable {
private final Dispatcher> dispatcher;
private final Function operation;
private final Supplier collectionFactory;
private final AtomicInteger seq = new AtomicInteger();
AsyncOrderedParallelCollector(
Function operation,
Supplier collection,
Executor executor,
int parallelism) {
this.dispatcher = new ThrottlingDispatcher<>(executor, parallelism);
this.collectionFactory = collection;
this.operation = operation;
}
AsyncOrderedParallelCollector(
Function operation,
Supplier collection,
Executor executor) {
this.dispatcher = new UnboundedDispatcher<>(executor);
this.collectionFactory = collection;
this.operation = operation;
}
@Override
public BiConsumer>>, T> accumulator() {
return (acc, e) -> {
int nextVal = seq.getAndIncrement();
acc.add(dispatcher.enqueue(() -> new AbstractMap.SimpleEntry<>(nextVal, operation.apply(e))));
};
}
@Override
public Function>>, CompletableFuture> finisher() {
if (dispatcher.getWorkingQueue().size() != 0) {
dispatcher.start();
return foldLeftFuturesOrdered(collectionFactory)
.andThen(f -> supplyWithResources(() -> f, dispatcher::close));
} else {
return supplyWithResources(() -> (__) -> completedFuture(collectionFactory
.get()), dispatcher::close);
}
}
@Override
public Set characteristics() {
return emptySet();
}
@Override
public void close() {
dispatcher.close();
}
private static > Function>>, CompletableFuture> foldLeftFuturesOrdered(Supplier collectionFactory) {
return futures -> futures.stream()
.reduce(completedFuture(synchronizedList(new ArrayList<>())),
accumulatingResults(),
mergingPartialResults())
.thenApply(list -> list.stream()
.sorted(Comparator.comparing(Entry::getKey))
.map(Entry::getValue)
.collect(Collectors.toCollection(collectionFactory)));
}
}