[英]Are objects that have no state always visible when published?
说我有一堂课
public class Foo {
public void printHi() {
System.out.print("Hi");
}
}
在某些客户端代码中,我做类似
public static void main() {
Foo foo = new Foo();
(new Thread(() -> {foo.printHi();})).start();
}
并取消调用线程启动之前发生的保证。 然后,使用该线程可能看不到Foo引用,或更糟的是,该类的方法不可见,但是Foo引用是可见的。 我不确定方法是如何存储在像字段这样的对象中的,但是这假设它只是属于该对象的内存中的某物,因此它可能存在可见性问题,但我不确定。 有人可以向我解释这部分吗?
我问这个是因为Foo是不可变的,在JCIP书中Goetz说
“另一方面,即使不使用同步来发布对象引用,也可以安全地访问不可更改的对象。为保证初始化安全,必须满足所有不变性要求:不可修改状态,所有领域是最终的,正确的构造” (Goetz,3.5.2)
但是,它没有任何final字段,因此是否算作所有字段都是final的? 由于没有字段=所有字段?
获得相同答案的方法有多种。
final
字段,因为没有字段不是final
字段。 即使在Foo
声明了一些非final
字段,也不读取对象状态的printHi()
调用也不会引起潜在的数据争用。 请注意,这仅适用于由new Foo(…)
表达式生成的Foo
确切实例,因为子类可以重写printHi()
以访问共享的可变状态。
必须强调竞争条件是关于共享的可变数据的,不一定是对象。 因此,如果printHi()
访问不同类的共享static
变量,则即使Foo
实例是不可变的和/或正确发布的,它也可能产生数据争用。 如果printHi()
不访问共享可变状态(或仅使用适当的防护),则在另一个线程中调用foo.printHi()
的代码是安全的。
正如Elliott Frisch提到的那样 ,lambda表达式无论如何都表现得像一个不可变的对象,因此即使没有Thread.start()
关系或Foo
的不可变性(假设Foo
实例之后没有修改)的发生 ,代码也将是安全的。
foo
必须 (有效) final
可以在此处使用。
Foo foo = null; // <-- for example,
foo = new Foo();
(new Thread(() -> {
foo.printHi(); // <-- compiler error
})).start();
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.