没有状态的对象在发布时是否始终可见?

Are objects that have no state always visible when published?

说我有一个 class

public class Foo {
    public void printHi() {
       System.out.print("Hi");
    }
}

在一些客户端代码中我做了类似

的事情
public static void main() {
     Foo foo = new Foo();
     (new Thread(() -> {foo.printHi();})).start();
}

并取消调用 Thread Start 的 happens-before 保证。 那么 Foo 引用是否可能对使用它的线程不可见,或者更糟的是,属于 class 的方法不可见,但 Foo 引用是可见的。我不确定方法是如何存储在像字段这样的对象中的,但这假设它只是内存中属于该对象的东西,所以它可能有可见性问题,但我不确定。有人也可以向我解释那部分吗?

我问这个是因为 Foo 是不可变的,Goetz 在 JCIP 书中说

"Immutable objects, on the other hand, can be safely accessed even when synchronization is not used to publish the object reference. For this guarantee of initialization safety to hold, all of the requirements for immutability must be met: unmodi-fiable state, all fields are final, and proper construction"(戈茨,3.5.2)

但是,它没有任何 final 字段,所以它算作所有字段都是 final 吗?由于没有字段 = 所有字段?

foo 必须(有效)final才能在此处使用。

Foo foo = null; // <-- for example,
foo = new Foo();
(new Thread(() -> {
    foo.printHi(); // <-- compiler error
})).start();

有不同的方法可以得到相同的答案。

  1. 您的对象是不可变的,因为它没有可以修改的状态。

  2. 它的所有字段都是 final,因为没有字段不是 final

  3. 没有可能的竞争条件,因为在访问时没有可以修改的数据。

  4. 即使在Foo中声明了一些非final字段,printHi()的调用不读取对象的状态,不承担任何责任潜在的数据竞争。请注意,这仅适用于 Foo 的确切实例,由 new Foo(…) 表达式生成,因为子 classes 可以覆盖 printHi() 以访问共享可变状态。

    需要强调的是,竞争条件是关于共享可变数据的,不一定是对象。因此,如果 printHi() 访问另一个 class 的共享 static 变量,它可能会产生数据竞争,即使 Foo 实例是不可变的 and/or 正确发布.如果 printHi() 不访问共享可变状态(或仅使用适当的保护),则在另一个线程中调用 foo.printHi() 的代码是安全的。

一样,lambda 表达式的行为无论如何都像一个不可变对象,因此即使没有 [=23= 的 happens-before 关系,代码也是安全的] 或 Foo 的不变性(假设 Foo 实例之后未被修改)。