【问题标题】:Why paralel stream could provide not full list of elements [duplicate]为什么并行流不能提供不完整的元素列表[重复]
【发布时间】:2017-12-22 12:09:15
【问题描述】:

我正在使用流将字符串数组转换为哈希图。

    String[] arguments= new String[]{"-a","1","-b","2","-c","3","-d","4","-e","5"};
    HashMap<String, String> params = new HashMap<>();
    IntStream.iterate(0, i -> i + 2)
            .limit(arguments.length / 2)
            .parallel()
            .forEach(i -> params.put(arguments[i], arguments[i + 1]));
    System.out.println(params.size());

它显示 5,但有时显示 4。

请您解释一下,导致不同结果的原因是什么?

【问题讨论】:

  • "我正在将字符串数组转换为 hashmap 使用流" 为什么?使用普通的for 循环。它更快、更简单、更清晰,而且有效!
  • 第 1 步:学习在没有forEach 的情况下解决问题。第 2 步:认识到并行流不会为这样一个微不足道的任务带来回报(尤其是对于并行不友好的 iterate(…).limit(…) 组合而言)。如果您想要一个高效的解决方案,您可以使用可以并行工作的HashMap&lt;String, String&gt; params = IntStream.range(0, arguments.length/2).map(i -&gt; i*2) .collect(HashMap::new, (m,i) -&gt; m.put(arguments[i], arguments[i+1]), Map::putAll);,但这里的并行处理仍然没有任何好处。

标签: java arrays string hashmap java-stream


【解决方案1】:

使用并行流时,操作必须无状态,否则由于线程调度差异,您将得到不确定的结果。

这一行:

.forEach(i -> params.put(arguments[i], arguments[i + 1]));

是每次执行结果不同的原因。

您的问题的解决方案是利用collect 归约操作并避免forEach

您可以在 JAVA Stream API 中找到有关无状态行为和副作用的更多信息。

【讨论】:

    【解决方案2】:

    您正在破坏基本的流属性 - 没有副作用。并且您的流通过forEach 产生了副作用。简而言之,您将来自多个线程的元素放入非线程安全集合HashMap

    正确的做法是通过以下方式收集:

    String[] arguments = new String[] { "-a", "1", "-b", "2", "-c", "3", "-d", "4", "-e", "5" };
        Map<String, String> map = IntStream.iterate(0, i -> i + 2)
                .limit(arguments.length / 2)
                .parallel()
                .boxed()
                .collect(Collectors.toMap(i -> arguments[i], i -> arguments[i + 1]));
    
        System.out.println(map); // {-a=1, -b=2, -c=3, -d=4, -e=5}
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-01-13
      • 1970-01-01
      • 2020-10-11
      • 2018-04-04
      • 2014-04-04
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多