使用java8流构建集合

时间:2016-02-19 18:11:24

标签: java concurrency java-8 java-stream

我编写了这段代码,使用Executor.newFixedThreadPool和ConcurrentLinkedQueue同时构建一个对象集合。但是,我发现整个线程池和任务提交给它冗长。我希望我能用流更简洁地写出来。

private ConcurrentLinkedQueue<ApiRunner> getRunners(final ApiRunnerBuilder builder,
        final int testSize) throws InterruptedException {

    final ExecutorService executor = Executors.newFixedThreadPool(NUM_OF_CORES);
    ConcurrentLinkedQueue<ApiRunner> runners = new ConcurrentLinkedQueue<ApiRunner>();
    for (int i = 0; i < testSize; i++) {
        executor.execute(() -> {
            runners.add(builder.build());
        });
    }
    executor.shutdown();
    executor.awaitTermination(300, TimeUnit.SECONDS);
    return runners;
}

我想也许它可以简化为这样的东西(java和java新手):

private ConcurrentLinkedQueue<ApiRunner> getRunners(final ApiRunnerBuilder builder,
        final int testSize) throws InterruptedException {

    ConcurrentLinkedQueue<ApiRunner> runners = new ConcurrentLinkedQueue<ApiRunner>();
    ConcurrentLinkedQueue<ApiRunner> runners = range(testSize).parallelStream(()-> {
            runners.add(builder.build());
        });
    }
    return runners;
}

2 个答案:

答案 0 :(得分:5)

既然你说过,你有很多I / O,我不建议使用流API。流API针对CPU绑定任务进行了优化,因为它根据CPU内核的数量调整线程数,但对于I / O绑定任务,当线程被阻塞等待完成时,可能会有更多的线程。 I / O操作不消耗CPU资源。

请注意,旧的API也适用于新的lambda表达式:

ExecutorService executor = Executors.newFixedThreadPool(DESIRED_CONCURRENCY);
ConcurrentLinkedQueue<ApiRunner> runners = new ConcurrentLinkedQueue<ApiRunner>();
executor.invokeAll(Collections.nCopies(testSize, ()->runners.add(builder.build())));
executor.shutdown();
return runners;

在实际应用程序中,您可能会使执行程序比此任务更长。方法invokeAll已经等待所有任务的完成,因此这里既不需要关闭也不等待终止。 shutdown调用仅在此示例中添加以进行清理,因为在这种情况下,您已在方法内部创建了执行程序。

答案 1 :(得分:4)

你可以这样做:

ConcurrentLinkedQueue<ApiRunner> runners =
    Stream.generate(() -> builder.build())
          .parallel()
          .limit(testSize)
          .collect(toCollection(ConcurrentLinkedQueue::new));