我有两个循环。在内部循环中,我点击数据库,获取结果并对结果执行一些计算(包括调用其他私有方法)并将结果放入映射中。
这种方法是否会导致任何问题,例如将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);
});
});
答案 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。添加到地图本身不是问题,就是为其创建并发哈希映射。
关于数据库,它取决于您查询它的方式以及您共享该对象的级别。如果为每个线程使用具有不同连接的连接池,则可能没问题。对于大多数数据库,共享连接并为每个线程获取新语句也没问题。共享语句并获取新的结果集会导致许多数据库驱动程序出现问题。