为什么在执行java并行流时list.size会发生变化?

wko9yo5t  于 2022-11-27  发布在  Java
关注(0)|答案(1)|浏览(188)
static void statefullParallelLambdaSet() {
        Set<Integer> s = new HashSet<>(
            Arrays.asList(1, 2, 3, 4, 5, 6)
        );

        List<Integer> list = new ArrayList<>();
        int sum = s.parallelStream().mapToInt(e -> {    // pipeline start
            if (list.size() <= 3) {     // list.size() changes while the pipeline operation is executing.
                list.add(e);            // mapToInt's lambda expression depends on this value, so it's stateful.
                return e;
            }
            else return 0;
        }).sum();   // terminal operation
        System.out.println(sum);
    }

在上面的代码中,它说list.size()在管道操作运行时发生变化,但我不明白。
因为list.add(e)是并行执行的,所以它会在多个线程中同时执行,那么假设每次执行时值都会改变是否正确呢?
值即使作为串行流执行也会改变的原因是因为它是一个集合,所以没有顺序,所以每次执行时绘制的数字都不一样...
我说的对吗?

9jyewag0

9jyewag01#

发生这种情况的原因是所谓的争用条件,CPU(即使是许多线程化CPU)运行的进程也比应用程序进程多,因此它可以解析并执行指令评估,然后必须跳出来为操作系统做一些事情,然后返回,应用程序的另一个并行进程设法通过它,因为核心/超线程没有从其工作中被窃取。
你可以在以下书籍中读到有关竞争条件的内容:https://link.springer.com/referenceworkentry/10.1007/978-0-387-09766-4_36
但是你应该做的是在你要修改的内存上实现锁来防止这种情况,在Java中你需要查看java.util.concurrent.Lockshttps://www.baeldung.com/java-concurrent-locks

相关问题