Java 8以并行流

时间:2016-03-31 06:20:56

标签: java concurrency java-8 concurrenthashmap

我有两个循环。在内部循环中,我点击数据库,获取结果并对结果执行一些计算(包括调用其他私有方法)并将结果放入映射中。 这种方法是否会导致任何问题,例如将null放入任何密钥?

没有两个线程会更新相同的值。即)计算的key将是唯一的。 (如果它循环n次,则会有n个密钥)

Map<String,String> m = new ConcurrentHashMap<>();
      obj1.getProp().parallelStream().forEach(k1 -> { //obj.getProp() returns a list
          obj2.parallelStream().forEach(k2-> { //obj2 is a list

              String key = constructKey(k1,k2);
             //Hit a DB and get the result
             //Computations on the result
             //Call some other methods
              m.put(key, result);
            });
        });

2 个答案:

答案 0 :(得分:2)

除非您完全理解它不仅仅是循环的替代拼写,否则不应使用Stream API。通常,如果您的代码在流上包含forEach,那么您应该至少问一次这是否真的是您的任务的最佳解决方案,但如果您的代码包含嵌套 {{ 1}}调用,你应该知道它不是正确的事情。

它可能会起作用,就像在你的问题中添加到并发映射时一样,它会破坏Stream API的目的。

除此之外,数组没有forEach方法,因此,当parallelStream()的结果类型和obj.getProp()的类型是数组时,正如您的评论所说,使用obj2构建流。

您想要做的事情可以实现为

Arrays.stream(…)

这样做的好处不仅在于更好地利用并行处理,而且即使您使用Map<String,String> m = Arrays.stream(obj1.getProp()).parallel() .flatMap(k1 -> Arrays.stream(obj2).map(k2 -> constructKey(k1, k2))) .collect(Collectors.toConcurrentMap(key -> key, key -> { //Hit a DB and get the result //Computations on the result //Call some other methods return result; })); ,也可以创建非并发Collectors.toMap,而不是Map。 ;该框架将以线程安全的方式生成它。

因此,除非您确实需要并发映射以进行后续的并发处理,否则您可以使用;哪一个会表现得更好取决于那些讨论会超出这个答案范围的因素。

因此,正确使用Stream API,它将是线程安全的,无论您生成哪种Collectors.toConcurrentMap类型,剩下的问题是数据库访问是否是线程安全的,{{3}取决于你在问题中没有包含的很多因素,所以我们无法回答这个问题。

答案 1 :(得分:1)

您的问题归结为部分&#34;我可以从多个线程添加到并发哈希映射吗?&#34;和&#34;我可以并行访问我的数据库吗?&#34;

第一个答案是:&#34;是&#34;,第二个答案是&#34;它取决于&#34;

或者更长一点:你使用的两个并行流基本上只是在执行池中的多个线程上启动内部lambda。添加到地图本身不是问题,就是为其创建并发哈希映射。

关于数据库,它取决于您查询它的方式以及您共享该对象的级别。如果为每个线程使用具有不同连接的连接池,则可能没问题。对于大多数数据库,共享连接并为每个线程获取新语句也没问题。共享语句并获取新的结果集会导致许多数据库驱动程序出现问题。