在并行流中的hashmap中插入值时的线程安全性

use*_*342 3 java concurrency hashmap concurrenthashmap java-8

我需要使用10秒的超时进行异步调用,并且需要对映射中的每个元素执行此操作.异步调用的结果存储在另一个映射中.HashMap在这种情况下使用是否安全或我需要使用ConcurrentMap

Map<String, String> x = ArrayListMultimap.create();
Map<String, Boolean> value = Maps.newHashMap();

x.keySet().paralleStream().forEach(req -> {
   try {
      Response response = getResponseForRequest(req);
      value.put(req, response.getTitle());
   } catch(TimeoutException e) {
      value.put(req, null);
   }
}
Run Code Online (Sandbox Code Playgroud)

这个线程安全吗?我无法理解.我知道另一种方法是创建一个并发的hashmap,并考虑一些其他填充值而不是null,因为Concurrent map不支持null值.

Szy*_*iak 6

您可以使用.map()而不是并行修改外部映射来代替.forEach()和返回使用Collectors.toMap()终止函数创建的映射.考虑以下示例:

Map result = x.keySet()
  .parallelStream()
  .map(req -> {
    try {
      Response response = getResponseForRequest(req);
      return new AbstractMap.SimpleEntry<>(req, response.getTitle());
    } catch (TimeoutException e) {
      return new AbstractMap.SimpleEntry<>(req, null);
    }
  })
  .collect(Collectors.toMap(AbstractMap.SimpleEntry::getKey, AbstractMap.SimpleEntry::getValue));
Run Code Online (Sandbox Code Playgroud)

在此示例中,您将返回一个SimpleEntry对象,该对象表示每个元素的键和值,并且在处理完所有条目后,您将它们收集到单个映射中.

简单化

Holger提出了更加简化的解决方案AbstractMap.SimpleEntry:

Map result = x.keySet()
  .parallelStream()
  .collect(Collectors.toMap(Function.identity(), req -> {
    try {
      Response response = getResponseForRequest(req);
      return response.getTitle()
    } catch (TimeoutException e) {
      return null
    }
  }));
Run Code Online (Sandbox Code Playgroud)

选择任何更适合你的方法.