【发布时间】:2017-02-28 17:29:48
【问题描述】:
Java 8 parallelStream 使用的线程似乎比系统属性 java.util.concurrent.ForkJoinPool.common.parallelism 指定的线程多。这些单元测试表明,我使用自己的 ForkJoinPool 使用所需数量的线程处理任务,但使用 parallelStream 时,线程数量高于预期。
import org.junit.Test;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import static org.junit.Assert.assertTrue;
public class ParallelStreamTest {
private static final int TOTAL_TASKS = 1000;
@Test
public void testParallelStreamWithParallelism1() throws InterruptedException {
final Integer maxThreads = 1;
System.setProperty("java.util.concurrent.ForkJoinPool.common.parallelism", maxThreads.toString());
List<Integer> objects = new ArrayList<>();
for (int i = 0; i < 1000; i++) {
objects.add(i);
}
final AtomicInteger concurrentThreads = new AtomicInteger(0);
final AtomicInteger taskCount = new AtomicInteger(0);
objects.parallelStream().forEach(i -> {
processTask(concurrentThreads, maxThreads); //expected to be called one at the time
taskCount.addAndGet(1);
});
assertTrue(taskCount.get() == TOTAL_TASKS);
}
@Test
public void testMyOwnForkJoinPoolWithParallelism1() throws InterruptedException {
final Integer threads = 1;
List<Integer> objects = new ArrayList<>();
for (int i = 0; i < TOTAL_TASKS; i++) {
objects.add(i);
}
ForkJoinPool forkJoinPool = new ForkJoinPool(1);
final AtomicInteger concurrentThreads = new AtomicInteger(0);
final AtomicInteger taskCount = new AtomicInteger(0);
forkJoinPool.submit(() -> objects.parallelStream().forEach(i -> {
processTask(concurrentThreads, threads); //expected to be called one at the time
taskCount.addAndGet(1);
}));
forkJoinPool.shutdown();
forkJoinPool.awaitTermination(1, TimeUnit.MINUTES);
assertTrue(taskCount.get() == TOTAL_TASKS);
}
/**
* It simply processes a task increasing first the concurrentThreads count
*
* @param concurrentThreads Counter for threads processing tasks
* @param maxThreads Maximum number of threads that are expected to be used for processing tasks
*/
private void processTask(AtomicInteger concurrentThreads, int maxThreads) {
int currentConcurrentThreads = concurrentThreads.addAndGet(1);
if (currentConcurrentThreads > maxThreads) {
throw new IllegalStateException("There should be no more than " + maxThreads + " concurrent thread(s) but found " + currentConcurrentThreads);
}
// actual processing would go here
concurrentThreads.decrementAndGet();
}
}
应该只有一个线程用于处理任务,因为 ForkJoinPool 有parallelism=1 和java.util.concurrent.ForkJoinPool.common.parallelism=1。因此,两个测试都应该通过,但 testParallelStreamWithParallelism1 失败:
java.lang.IllegalStateException: 应该有不超过 1 个并发线程,但找到了 2 个
似乎设置 java.util.concurrent.ForkJoinPool.common.parallelism=1 没有按预期工作,同时处理了超过 1 个并发任务。
有什么想法吗?
【问题讨论】:
-
@4castle 感谢您的指出,我已更正 testMyOwnForkJoinPoolWithParallelism1 以使用 parallelStream 并且在 testParallelStreamWithParallelism1 失败时按预期通过
标签: java multithreading java-8 java-stream