![]() |
1
15
如果另一个线程要检查
基本上,如果没有适当的锁(或静态初始化器等提供的保证),就不要共享数据:严重地说,内存模型是非常棘手的,一般来说,无锁编程也是如此。尽量避免这种情况成为可能。 在 符合逻辑的 转让条款 之后 构造器运行-所以如果您观察变量 从同一条线 它在构造函数调用期间将为空。然而,正如我所说,有记忆模型的奇怪之处。
编辑:为了进行双重检查锁定,您可以摆脱这种情况。
如果
你的领域是
编辑:这是我反对阿龙的观点的理由,因为它是一条线。假设我们有:
我相信这会的
总是
报告
然后从 section 17.4.5 : 两个动作可以由一个发生在关系之前的动作来命令。如果一个动作先于另一个动作发生,那么第一个动作对第二个动作可见并在第二个动作之前排序。
换句话说,即使是在一条线内,也可以发生奇怪的事情。 但不能被观察到 . 在这种情况下,差异 将 可见,这就是为什么我认为这是非法的。 |
![]() |
2
8
在第一种情况下,VM将执行此代码(伪代码):
所以在这种情况下,
在第二种情况下,将运行来自构造函数的代码,将返回引用(就像在普通方法调用中一样),并将someobject设置为引用的值 之后 所有初始化代码都已运行。
问题是没有办法告诉Java不要分配。
但是由于没有使用tmp,优化器可以忽略它,因此它将生成与上面相同的代码。 因此,这种行为允许优化器生成更快的代码,但在编写多线程代码时,它可能会让您感到恶心。在单线程代码中,这通常不是问题,因为在构造函数完成之前不会执行任何代码。 [编辑]这是一篇很好的文章,解释了正在发生的事情: http://www.ibm.com/developerworks/java/library/j-dcl.html PS:书 Effective Java, Second Edition “Joshua Bloch包含Java 5和UP的解决方案:
看起来奇怪,但应该在每个Java虚拟机上工作。请注意,每一位都很重要;如果省略了双赋值,则会得到性能不佳的对象或部分初始化的对象。要得到完整的解释,请买这本书。 |
![]() |
3
2
|
![]() |
4
0
在另一个线程中,在构造函数完成执行之前,您的对象仍然为空。这就是为什么如果构造被异常终止,引用将保持为空的原因。
哪里
确保在另一个对象上同步,而不是正在构造的对象。 |
![]() |
5
0
这是一些测试代码 在构造函数完成运行之前,对象为空。 :
输出: null Slow constructor has started null null null null null Slow constructor has finished s1 is set, s2 is set s1 is set, s2 is set s1 is set, s2 is set s1 is set, s2 is set |
![]() |
6
-1
对于第一个示例:在构造函数完成后,SomeObject变为非空。如果要从另一个线程进行检查,则在构造函数完成后,某些对象将变为非空。注意,您不应该从不同的线程访问未同步的对象,因此您的示例不应该在实际代码中以这种方式实现。 对于第二个示例,SomeObject永远不会为空,因为它是在构建SomeClass本身并使用新创建的对象创建和初始化SomeObject之后构建的。这里的线程也一样:不要在没有同步的情况下从不同的线程访问这个变量! |