繁体   English   中英

java 8并行流混淆/问题

[英]java 8 parallel stream confusion/issue

我是并行流的新手,并试图制作一个计算值* 100(1到100)并将其存储在地图中的示例程序。 在执行代码时,每次迭代都会有不同的数量。 我可能在某个地方错了所以请指导我,任何人都知道正确的方法。

代码

import java.util.*;
import java.lang.*;
import java.io.*;
import java.util.stream.Collectors;

public class Main{    
    static int l = 0;       
    public static void main (String[] args) throws java.lang.Exception {
        letsGoParallel();
    }       
    public static int makeSomeMagic(int data) {
        l++;
        return data * 100;
    }        
    public static void letsGoParallel() {
        List<Integer> dataList = new ArrayList<>();
        for(int i = 1; i <= 100 ; i++) {
            dataList.add(i);
        }
        Map<Integer, Integer> resultMap = new HashMap<>();
        dataList.parallelStream().map(f -> {
            Integer xx = 0;
            {
                xx = makeSomeMagic(f);
            }
            resultMap.put(f, xx);
            return 0;
        }).collect(Collectors.toList());
        System.out.println("Input Size: " + dataList.size());
        System.out.println("Size: " + resultMap.size());
        System.out.println("Function Called: " + l);
    }
}

可运行代码

最后输出

输入大小:100

尺寸:100

功能称为:98

每次运行输出都不同。 我想在我自己的应用程序中使用并行流,但由于这种混淆/问题我不能。 在我的应用程序中,我有100-200个唯一编号,需要执行相同的操作。 简而言之,它有处理某些东西的功能。

您对HashMapl变量的访问都不是线程安全的,这就是每次运行时输出不同的原因。

执行您要执行的操作的正确方法是将Stream元素收集到Map

Map<Integer, Integer> resultMap =
    dataList.parallelStream()
            .collect(Collectors.toMap (Function.identity (), Main::makeSomeMagic));

编辑:使用此代码仍然以线程安全的方式更新l变量,因此如果变量的最终值对您很重要,则必须添加自己的线程安全性。

通过在resultMap放置一些值,您将使用副作用

 dataList.parallelStream().map(f -> {
            Integer xx = 0;
            {
                xx = makeSomeMagic(f);
            }
            resultMap.put(f, xx);
            return 0;
        })

API声明:

无状态操作(例如过滤器和映射)在处理新元素时不保留先前看到的元素的状态 - 每个元素都可以独立于其他元素上的操作进行处理。

事情

如果流操作的行为参数是有状态的,则流管道结果可能是不确定的或不正确的。 有状态lambda(或实现适当功能接口的其他对象)的结果取决于在流管道执行期间可能发生变化的任何状态。

它遵循一个类似于你的例子显示:

...如果映射操作是并行执行的,由于线程调度的差异,相同输入的结果可能因运行而异,而对于无状态lambda表达式,结果将始终相同。

这解释了你的观察: 每次运行输出都不同。

@Eran 显示了正确的方法

希望它工作正常。 通过制作Synchronied函数makeSomeMagic并使用Threadsafe数据结构ConcurrentHashMap并编写简单语句

dataList.parallelStream().forEach(f -> resultMap.put(f, makeSomeMagic(f)));

整个代码在这里:

import java.util.*;
import java.lang.*;
import java.io.*;
import java.util.stream.Collectors;

public class Main{  
static int l = 0;
  public static void main (String[] args) throws java.lang.Exception {
    letsGoParallel();
  }
  public synchronized static int makeSomeMagic( int data) { // make it synchonized
    l++;
    return data * 100;
  }
  public static void letsGoParallel() {
    List<Integer> dataList = new ArrayList<>();
    for(int i = 1; i <= 100 ; i++) {
      dataList.add(i);
    }
    Map<Integer, Integer> resultMap = new ConcurrentHashMap<>();// use ConcurrentHashMap
    dataList.parallelStream().forEach(f -> resultMap.put(f, makeSomeMagic(f)));
    System.out.println("Input Size: " + dataList.size());
    System.out.println("Size: " + resultMap.size());
    System.out.println("Function Called: " + l);
  }
}
  • 无需计算方法调用的次数。
  • Stream将帮助您循环使用字节代码。
  • 将您的逻辑(函数)传递给Stream ,不要在多线程中使用没有线程安全的变量(包括parallelStream

像这样。

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

public class ParallelStreamClient {
//  static int l = 0;---> no need to count times.

    public static void main(String[] args) throws java.lang.Exception {
        letsGoParallel();
    }

    public static int makeSomeMagic(int data) {
//  l++;-----> this is no thread-safe way
    return data * 100;
}

public static void letsGoParallel() {
    List<Integer> dataList = new ArrayList<>();
    for (int i = 1; i <= 100; i++) {
        dataList.add(i);
    }
    Map<Integer, Integer> resultMap =         
    dataList.parallelStream().collect(Collectors.toMap(i -> i,ParallelStreamClient::makeSomeMagic));
    System.out.println("Input Size: " + dataList.size());
    System.out.println("Size: " + resultMap.size());
    //System.out.println("Function Called: " + l);       
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM