我已经从数据库中进行了两次单独的并行读取实现。
第一个实现是使用ExecutorService
和newCachedThreadPool()
构造函数和Futures:我只是进行一个调用,为每个读取案例返回一个未来,然后在我调用get()
之后进行所有调用。这个实现工作正常,而且足够快。
第二个实现是使用并行流。当我将并行流调用放入同一个ExecutorService
池时,它几乎慢5倍并且它似乎没有使用我希望的那么多线程。当我把它放入ForkJoinPool pool = new ForkJoinPool(50)
时,它的工作速度与之前的实现一样快。
我的问题是:
为什么并行流利用newCachedThreadPool
版本中的线程?
这是第二个实现的代码(我没有发布第一个实现,因为无论如何都可以正常工作):
private static final ExecutorService pool = Executors.newCachedThreadPool();
final List<AbstractMap.SimpleImmutableEntry<String, String>> simpleImmutableEntryStream =
personIdList.stream().flatMap(
personId -> movieIdList.stream().map(
movieId -> new AbstractMap.SimpleImmutableEntry<>(personId, movieId))).collect(Collectors.toList());
final Future<Map<String, List<Summary>>> futureMovieSummaryForPerson = pool.submit(() -> {
final Stream<Summary> summaryStream = simpleImmutableEntryStream.parallelStream().map(
inputPair -> {
return FeedbackDao.find(inputPair.getKey(), inputPair.getValue());
}).filter(Objects::nonNull);
return summaryStream.collect(Collectors.groupingBy(Summary::getPersonId));
});
答案 0 :(得分:2)
这与{{3}}的实现方式有关,如果当前线程来自ForkJoinPool
,它将使用相同的池来提交新任务,但如果不是,它将使用公共池与本地计算机中的处理器总数以及使用Executors.newCachedThreadPool()
创建池时的处理程序,此池创建的线程不会被识别为来自ForkJoinPool
,因此它使用公共池。
以下是它的实现方式,它可以帮助您更好地理解:
public final ForkJoinTask<V> fork() {
Thread t;
if ((t = Thread.currentThread()) instanceof ForkJoinWorkerThread)
((ForkJoinWorkerThread)t).workQueue.push(this);
else
ForkJoinPool.common.externalPush(this);
return this;
}
池Executors.newCachedThreadPool()
创建的线程不属于ForkJoinWorkerThread
类型,因此它将使用优化池大小不足的公共池来提交新任务。