编程语言
首页 > 编程语言> > java – 为什么共享可变性不好?

java – 为什么共享可变性不好?

作者:互联网

我正在观看关于Java的演讲,有一次,讲师说:

“可变性是可以的,分享是好的,共享的可变性是魔鬼的工作.”

他所指的是以下一段代码,他认为这是一种“极其糟糕的习惯”:

//double the even values and put that into a list.
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 1, 2, 3, 4, 5);
List<Integer> doubleOfEven = new ArrayList<>();

numbers.stream()
       .filter(e -> e % 2 == 0)
       .map(e -> e * 2)
       .forEach(e -> doubleOfEven.add(e));

然后他继续编写应该使用的代码,即:

List<Integer> doubleOfEven2 =
      numbers.stream()
             .filter(e -> e % 2 == 0)
             .map(e -> e * 2)
             .collect(toList());

我不明白为什么第一段代码是“坏习惯”.对我而言,他们都达到了同样的目标.

解决方法:

对第一个示例代码段的说明

执行并行处理时,问题就出现了.

//double the even values and put that into a list.
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 1, 2, 3, 4, 5);
List<Integer> doubleOfEven = new ArrayList<>();

numbers.stream()
       .filter(e -> e % 2 == 0)
       .map(e -> e * 2)
       .forEach(e -> doubleOfEven.add(e)); // <--- Unnecessary use of side-effects!

这不必要地使用副作用,而如果在使用流时正确使用并非所有副作用都是坏的,则必须提供在不同输入部分上同时执行的行为.即编写不访问共享可变数据的代码来完成其工作.

这条线:

.forEach(e -> doubleOfEven.add(e)); // Unnecessary use of side-effects!

不必要地使用副作用,并行执行时,ArrayList的非线程安全性会导致错误的结果.

不久前,我读了一篇由Henrik Eichenhardt撰写的关于why a shared mutable state is the root of all evil.回复的博客

这是为什么共享可变性不好的简短推理;从博客中提取.

non-determinism = parallel processing + mutable state

This equation basically means that both parallel processing and
mutable state combined result in non-deterministic program behaviour.
If you just do parallel processing and have only immutable state
everything is fine and it is easy to reason about programs. On the
other hand if you want to do parallel processing with mutable data you
need to synchronize the access to the mutable variables which
essentially renders these sections of the program single threaded. This is not really new but I haven’t seen this concept expressed so elegantly. A non-deterministic program is broken.

这个博客继续推导出内部细节,以确定为什么没有正确同步的并行程序被破坏,你可以在附加的链接中找到.

对第二个示例代码段的说明

List<Integer> doubleOfEven2 =
      numbers.stream()
             .filter(e -> e % 2 == 0)
             .map(e -> e * 2)
             .collect(toList()); // No side-effects! 

这使用收集器对此流的元素使用收集缩减操作.

这样更安全,更高效,更易于并行化.

标签:java,java-8,java-stream,immutability
来源: https://codeday.me/bug/20191003/1850972.html