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

安全发布以及不可变与有效不可变的优势

朱鸿畅
2023-03-14
问题内容

我正在重读Java Concurrency in Practice,但不确定我是否完全了解有关不变性和安全发布的章节。

这本书说的是:

不可变对象可以由任何线程安全地使用,而无需额外的同步,即使不使用同步来发布它们也是如此。

我不明白的是,为什么有人(有 兴趣使自己的代码正确无误 )发布不安全的参考资料?

如果对象是不可变的,并且不安全地发布,那么我知道获得该对象引用的任何其他线程都将看到其正确状态,这是由于适当的不可变性(带有final字段等)提供了保证。

但是,如果发布是不安全的,则在发布后可能仍会看到另一个线程null或该发布之前的引用,而不是对不可变对象的引用,在我看来这似乎是没人希望的。

而且,如果使用安全发布来确保所有线程都能看到新引用,那么即使对象实际上是 不可变的
(没有final字段,也没有使它们静音的方法),那么一切都将再次变得安全。正如书中所说:

安全发布的 有效不变 对象可以被任何线程安全使用,而无需额外的同步。

那么,为什么不变性(相对于有效不变性)如此重要?在什么情况下会要求发表不安全的出版物?


问题答案:

出于以下两个原因,需要设计不需要同步的对象:

  1. 对象的用户可能会忘记同步。
  2. 即使开销很小,同步也不是免费的,尤其是当您的对象不经常被许多不同的线程使用时。

由于上述原因非常重要,因此最好学习有时困难的规则,并以编写者的身份创建不需要同步的安全对象,而不是希望代码的所有用户都记住正确使用它。

还请记住,作者并不是说对象是不安全发布的,它是在没有同步的情况下安全发布的。

关于您的第二个问题,我刚刚检查了一下,而书中并未保证其他线程将始终看到对更新对象的引用,只是如果这样做,它将看到完整的对象。但是我可以想象,如果它是通过另一个(Runnable?)对象的构造函数发布的,那将是美好的。但这确实有助于解释所有情况。

编辑:

有效不可变和不可变有效不可变和不可变
之间的区别是,在第一种情况下,您仍然需要以安全的方式发布对象。对于真正的不可变对象,这是不需要的。因此,首选真正不变的对象,因为出于上述原因,它们更易于发布。



 类似资料:
  • 及其不安全的发布: 可以抛出AssertionError,我同意。作者写道,这是因为不安全的出版,但另一方面没有答案:什么才是正确的出版方式?它们表示了4个安全发布习惯用语,但我不明白,为什么它们会在上面的情况下起作用: 要安全地发布对象,必须同时使对对象的引用和对象的状态对其他线程可见。通过以下方法可以安全地发布构造正确的对象: null 这里是我的第一个问题,谢谢你的帮助!

  • 我想确保我正确理解根据Java内存模型的‘有效不可变对象’行为。 假设我们有一个可变类,我们希望将它发布为一个有效不可变的类: 我们执行以下操作: 问题是:Java内存模型是否保证所有线程必须具有? 根据Java并发实践,这应该是正确的,但如果我错了,请纠正我。 3.5.3.安全发布习语 要安全地发布对象,必须同时使对对象的引用和对象的状态对其他线程可见。通过以下方法可以安全地发布正确构造的对象:

  • 问题内容: 好吧,考虑下面给出的不可变类: 现在,我正在一个类中创建一个对象,该对象的对象将由多个线程共享: 看到as 并移入同步块并创建对象。现在,由于 Java内存模型(JMM)允许多个线程在初始化开始之后但尚未结束之前观察对象。 因此,可以将写入操作视为在写入的字段之前发生。因此,因此可以看到部分构造,该构造很可能处于无效状态,并且其状态以后可能会意外更改。 它不是非线程安全的吗? 编辑 好

  • 问题内容: 我正在努力使可变对象与不可变对象有关。使用可变对象会带来很多负面影响(例如,从方法中返回字符串数组),但是我很难理解它的负面影响。使用可变对象的最佳实践是什么?您是否应尽可能避免使用它们? 问题答案: 好吧,这有几个方面。 没有参考身份的可变对象会在奇数时间导致错误。例如,考虑使用基于值的方法的 : 当实例用作键时,实例在映射中“丢失”,因为实例和相等性基于可变值。这些值在映射之外更改

  • 问题内容: 这是Java Concurrency in Practice中的一句话 共享的只读对象包括不可变的和实际上不可变的对象。 不变对象和有效不变对象之间有什么区别? 问题答案: 不可扩展且其字段全部为自身且不可变的类的实例是不可变的。 由于其方法的详细信息而无法更改其字段的类的实例实际上是不可变的。例如: 的某些实例实际上是不可变的,而有些则不是。 另一个例子是零长度数组。它们实际上是不可