当前位置: 首页 > 面试题库 >

为什么共享可变性不好?

郭璞
2023-03-14
问题内容

我正在观看有关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 的博客,回答
为什么共享的可变状态是万恶之源。

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

非确定性=并行处理+可变状态

该方程式基本上意味着并行处理和可变状态组合都会导致 不确定的程序行为
。如果您仅执行并行处理并且仅具有不变状态,那么一切都很好,并且很容易推理出程序。另一方面,如果要对可变数据进行并行处理,则需要同步对可变变量的访问,这实际上使程序的这些部分变为单线程。这并不是真正的新事物,但是我还没有看到这个概念如此优雅地表达。
一个不确定的程序被破坏了

该博客继续得出内部细节,以解释为什么没有正确同步的并行程序被破坏,您可以在附加的链接中找到这些细节。

第二个示例代码段的说明

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

这会使用来对该流的元素使用 缩减 收集操作Collector

这样更 安全 ,更 有效 并且更易于并行化。



 类似资料:
  • 问题内容: 我正在观看有关Java的演示,有一次讲师说: “可变性还可以,共享很好,共享可变性是魔鬼的工作。” 他指的是以下代码,他认为这是“极度坏习惯”: 然后,他着手编写应使用的代码,即: 我不明白为什么第一段代码是“不良习惯”。对我来说,他们都实现了相同的目标。 问题答案: 当执行并行处理时,该问题就起作用了。 在使用流时,这不必要地使用了 副作用, 但如果正确使用,并非所有副作用都不好,因

  • 正如你可以看到在这种情况下,虽然我们更改了的值,的值没有改变。 这是因为的类型,是不可变的。 在JavaScript内置类型中,以下是不可变的: Boolean Number Symbol Null Object Array String是一种不常见的情况,因为它可以使用进行迭代,并像数组一样提供数字索引器,但会执行以下操作:

  • 本文向大家介绍String 为什 么是不可变的?相关面试题,主要包含被问及String 为什 么是不可变的?时的应答技巧和注意事项,需要的朋友参考一下 简单的来说:String 类中使用 final 关键字修饰字符数组来保存字符串,`private final char value[]`,所以 String 对象是不可变的。而StringBuilder 与 StringBuffer 都继承自 Ab

  • 场景:nestjs modules 使用app.service 是否需要注册? 我想实现的大致如下: 以上不行!? 理论上来说我在app.module.ts中使用了providers应该是全局共享的呀?还是说我理解的有错误? 预期:在其他的modules使用app的方法的时候可以不用注册、辛苦有相关的伙伴指点一下、感谢

  • 问题内容: 每个线程都有自己的堆栈,但是它们共享一个公共堆。 所有人都清楚堆栈是用于局部/方法变量,堆是用于实例/类变量。 在线程之间共享堆有什么好处。 有多个线程同时运行,因此共享内存可能导致诸如并发修改,互斥等开销的问题。堆中的线程共享哪些内容。 为什么会这样呢?为什么每个线程也不拥有自己的堆?谁能提供一个现实的例子,线程如何利用共享内存? 问题答案: 要将数据从一个线程传递到另一个线程时该怎

  • 本文向大家介绍什么是秘密共享?相关面试题,主要包含被问及什么是秘密共享?时的应答技巧和注意事项,需要的朋友参考一下 回答:秘密共享是用于在区块链中提供数据安全性的主要方法之一。这种方法将个人信息或机密信息分为不同的单元,然后将其发送给网络上的用户。原始信息共享给分配了秘密共享的参与者。