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

JB *_*zet 24 java multithreading immutability

我正在重新阅读Java Concurrency In Practice,我不确定我是否完全理解有关不可变性和安全发布的章节.

这本书的内容是:

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

我不明白的是,为什么有人(有兴趣使他的代码正确)不安全地发布一些参考?

如果对象是不可变的,并且它是不安全地发布的,我理解获得对该对象的引用的任何其他线程将看到其正确的状态,因为由适当的不变性提供的保证(使用final字段等).

但是如果发布是不安全的,那么另一个线程可能仍然会null在发布之后看到或者之前的引用,而不是对不可变对象的引用,这对我来说似乎是没有人愿意的.

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

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

那么,为什么不变性(与有效不变性相比)如此重要?在什么情况下需要不安全的出版物?

Thi*_*ler 9

希望设计不需要同步的对象有两个原因:

  1. 对象的用户可能忘记同步.
  2. 尽管开销非常小,但同步并不是免费的,特别是如果您的对象不经常使用并且由许多不同的线程使用.

由于上述原因非常重要,因此最好学习有时很难的规则,作为编写者,制作不需要同步的安全对象,而不是希望代码的所有用户都记得正确使用它.

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

关于你的第二个问题,我刚刚检查过,本书并没有向你承诺另一个线程将始终看到对更新对象的引用,只要它确实如此,它将看到一个完整的对象.但我可以想象,如果它是通过另一个(Runnable?)对象的构造函数发布的,那将是很好的.这确实有助于解释所有案例.

编辑:

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


Joo*_*kka 5

那么,为什么不变性(与有效不变性相比)如此重要?

我认为重点是真正的不可变对象以后更难打破.如果你宣布了一个字段final,那么它就是最后一个字段.你必须删除它final才能更改该字段,并且应该响起警报.但是,如果你最初离开final了,有人可能会不小心添加一些改变字段的代码,并且繁荣 - 你搞砸了 - 只有一些添加的代码(可能在子类中),不修改现有代码.

我还假设显式不变性使得(JIT)编译器能够进行一些优化,否则这些优化很难或无法证明.例如,在使用volatile字段时,运行时必须保证与写入和读取线程的先发生关系.在实践中,这可能需要内存屏障,禁用无序执行优化等 - 即性能损失.但是如果对象是(深度)不可变的(仅包含final对其他不可变对象的引用),那么可以放松需求而不会破坏任何东西:只需要编写和读取单个引用,而不是整个引用,就可以保证发生之前的关系对象图.

因此,显式不变性使程序更简单,因此人们更容易推理和维护,并且更容易使计算机以最佳方式执行.随着对象图的增长,这些好处呈指数级增长,即对象包含包含对象的对象 - 如果一切都是不可变的,那么这一切都很简单.当需要可变性时,将其本地化到严格定义的位置并保持其他一切不可变仍然会带来很多好处.