如何使用java并行流而不是executorThreadsPool?

时间:2016-04-04 12:20:41

标签: java multithreading parallel-processing java-8 java-stream

我想编写一个测试,对我的API执行许多并行调用。

ExecutorService executor = Executors.newCachedThreadPool();
        final int numOfUsers = 10;
        for (int i = 0; i < numOfUsers; i++) {
            executor.execute(() -> {
                final Device device1 = getFirstDevice();
                final ResponseDto responseDto = devicesServiceLocal.acquireDevice(device1.uuid, 4738);
                if (responseDto.status == Status.SUCCESS)
                {
                    successCount.incrementAndGet();
                }
            });
        }

我知道我可以使用executorThreadsPool来完成它,就像这样:

devicesList.parallelStream()
           .map(device -> do something)

我可以用java8并行流创建它:

我如何在一台设备上执行此操作?

意思是我很少想要获得相同的设备。

类似的东西:

{{device}}.parallelStream().execute(myAction).times(10)

1 个答案:

答案 0 :(得分:1)

是的,但是......

你会想到

Stream.generate(() -> device)
      .limit(10)
      .parallel()
      .forEach(device -> device.execute());

应该做的工作。但不,因为原因(我真的不知道为什么,没有线索)。 如果我让device.execute()等一下,然后让它打印一些东西。流每秒打印10次。所以它并非完全平行,而不是你想要的。

谷歌是我的朋友,我发现很多文章都警告过parallelStream。但我的目光落在http://blog.jooq.org/2014/06/13/java-8-friday-10-subtle-mistakes-when-using-the-streams-api/ 8号和9号.8说如果它是由一个集合支持你必须对它进行排序,它会神奇地起作用:

Stream.generate(() -> device)
      .limit(10)
      .sorted((a,b)->0) // Sort it (kind of), what??
      .parallel()
      .forEach(device -> device.execute());

现在它在一秒钟后打印8次,在另一秒钟后打印2次。我有8个内核,所以我们(有点)期望。

我在我的信息流中使用了.forEach(),但起初我(就像你的例子)使用.map().map()没有打印出来的东西:流从未消耗过(参见链接文章中的9)。

因此,请注意使用流,尤其是并行流。你必须确保你的流被消耗,它是有限的(.limit()),它是并行的,等等。流很奇怪,我建议保留你的工作解决方案。

注意:如果device.execute()是一个阻止操作(IO,网络......),那么你将永远不会超过你的核心数量(在我的情况下为8个),这些任务将同时执行。< / p>

更新(感谢Holger):

霍尔格给出了一个优雅的选择:

IntStream.range(0,10)
      .parallel()
      .mapToObject(i -> getDevice())
      .forEach(device -> device.execute());

// Or shorter:
IntStream.range(0,10)
      .parallel()
      .forEach(i -> getDevice().execute());

就像一个并行的for循环(它可以工作)。