Java并行流填充数组

Java并行流填充数组,java,java-stream,java-10,Java,Java Stream,Java 10,我有一个非常大的hashmap,它充满了素数 var mapA = new HashMap<Integer, Long>(); 我添加了synchronized,因为流是并行运行的,所以我不希望在两个或更多线程同时在res中添加数据时出现争用条件 我已经尝试删除同步的(这个),程序仍然可以正常工作。但我如何才能确保它始终工作良好 多谢各位 如果需要,我将在这里添加整个代码: import java.util.*; import java.util.stream.Collector

我有一个非常大的hashmap,它充满了素数

var mapA = new HashMap<Integer, Long>();
我添加了
synchronized
,因为流是并行运行的,所以我不希望在两个或更多线程同时在
res
中添加数据时出现争用条件

我已经尝试删除同步的(这个),程序仍然可以正常工作。但我如何才能确保它始终工作良好

多谢各位


如果需要,我将在这里添加整个代码:

import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

public class DiffieHellman {

    private static final int LIMIT = 65536;

    private final long p;
    private final long g;

    public DiffieHellman(long p, long g) {
        this.p = p;
        this.g = g;
    }

    public List<Integer> tryBruteForce(long publicA, long publicB) {
        List<Integer> res = new ArrayList<Integer>();

        var mapA = new HashMap<Integer, Long>(
                IntStream
                        .rangeClosed(0, LIMIT)
                        .parallel()
                        .boxed()
                        .collect(
                                Collectors.toMap(x -> x, x -> DiffieHellmanUtils.modPow(publicB, x, p))
                        )
        );

        var mapB = new HashMap<Integer, Long>(
                IntStream
                        .rangeClosed(0, LIMIT)
                        .parallel()
                        .boxed()
                        .collect(
                                Collectors.toMap(x -> x, x -> DiffieHellmanUtils.modPow(publicB, x, p))
                        )
        );

        mapA.entrySet()
                    .parallelStream()
                    .forEach( x -> {

                        var values = mapB.entrySet()
                                        .parallelStream()
                                        .filter( y -> y.getValue().equals(x.getValue()))
                                        .map(Map.Entry::getKey)
                                        .toArray(Integer[]::new);

                        Arrays.stream(values)
                                .parallel()
                                .sorted()
                                .forEach(val -> {
                                        res.add(x.getKey());
                                        res.add((Integer) val);
                                });


                    });

        return res;
    }

}
import java.util.*;
导入java.util.stream.collector;
导入java.util.stream.IntStream;
公共类难题{
专用静态最终整数限值=65536;
私人最终长p;
私人最终长g;
公共难题Hellman(长p,长g){
这个,p=p;
这个.g=g;
}
公共列表tryBruteForce(长publicA,长publicB){
List res=new ArrayList();
var mapA=新HashMap(
IntStream
.rangeClosed(0,限制)
.parallel()
.boxed()
.收集(
Collectors.toMap(x->x,x->DiffieHellmanUtils.modPow(publicB,x,p))
)
);
var mapB=新HashMap(
IntStream
.rangeClosed(0,限制)
.parallel()
.boxed()
.收集(
Collectors.toMap(x->x,x->DiffieHellmanUtils.modPow(publicB,x,p))
)
);
mapA.entrySet()
.parallelStream()
.forEach(x->{
var values=mapB.entrySet()
.parallelStream()
.filter(y->y.getValue().equals(x.getValue()))
.map(map.Entry::getKey)
.toArray(整数[]::新建);
Arrays.stream(值)
.parallel()
.已排序()
.forEach(val->{
res.add(x.getKey());
res.add((整数)val);
});
});
返回res;
}
}

当然,您可以像其他答案所指出的那样简单地使用同步集合,但由于存在争用,这可能性能不够,编写起来仍然相当麻烦

相反,您可以通过习惯性地使用流API以稍微不同的方式来解决这个问题

首先,嵌套操作可以在单个流管道中完成:

mapB.entrySet()
            .parallelStream()
            .filter(y -> y.getValue().equals(x.getValue()))
            .map(y -> y.getKey())
            .sorted()
            .forEach(val -> {

                synchronized (this) {
                    res.add(x.getKey());
                    res.add((Integer) val);
                }
            });
其次,为了避免并发问题,最简单的方法是放弃命令式方法并利用流API的声明性

为了做到这一点,我们不会手动为每个添加
,然后将
元素添加到结果中,而是让流来管理它

这里要做的是创建一个新序列,方法是将
mapA
entrySet()的每个元素替换为自定义序列:

List<Integer> res = mapA.entrySet()
      .parallelStream()
      .flatMap(x -> mapB.entrySet().stream()
         .filter(y -> y.getValue().equals(x.getValue()))
         .map(Map.Entry::getKey)
         .sorted()
         .flatMap(v -> Stream.of(x.getKey(), v)))
      .collect(Collectors.toList());
List res=mapA.entrySet()
.parallelStream()
.flatMap(x->mapB.entrySet().stream())
.filter(y->y.getValue().equals(x.getValue()))
.map(map.Entry::getKey)
.已排序()
.flatMap(v->Stream.of(x.getKey(),v)))
.collect(Collectors.toList());

嵌套的
parallelStream
可以省略,因为
flatMap
正在流上调用
sequential()

我真的怀疑将
synchronized
parallelStream
一起使用是个好主意。或者,即使在一般情况下,如果操作本质上是原子的,我最好使用更适合和更接近我的需求的数据结构@HadiJ我已经更新了代码,我忘记粘贴代码了,值只是一个整数数组!在名为“res”的数组中,插入的键和值是否必须排序?@burakkyıldız yes
mapB.entrySet()
            .parallelStream()
            .filter(y -> y.getValue().equals(x.getValue()))
            .map(y -> y.getKey())
            .sorted()
            .forEach(val -> {

                synchronized (this) {
                    res.add(x.getKey());
                    res.add((Integer) val);
                }
            });
List<Integer> res = mapA.entrySet()
      .parallelStream()
      .flatMap(x -> mapB.entrySet().stream()
         .filter(y -> y.getValue().equals(x.getValue()))
         .map(Map.Entry::getKey)
         .sorted()
         .flatMap(v -> Stream.of(x.getKey(), v)))
      .collect(Collectors.toList());