在对象 Y 上定义的同步块中访问对象 X 是否安全?

Is it safe to access an object X within a synchronized block defined on object Y?

在同步方法或块中访问对象的状态是否安全这个问题有答案。我的问题:在同步块中访问对象 X 是否安全,其中同步块位于另一个对象 Y 上,并且 X 存在多个编写器线程?

public class X{
    private int value = 0;
    /** set method will be invoked by multiple threads**/
    public void set(int v){
       this.value = v;
   }
   public int value(){
       return value;
   }
}

public class Tester{
    private final Object Y = new Object();
    public void test(X x){
        synchronized(Y){
            System.out.println(x.value()); // is it guaranteed that x.value will be read from memory and not from the current thread's cache ?
        }
    }
}      

我知道在其上定义了同步块的对象的状态无需 volatile 即可安全访问,但是如果在另一个对象上定义了同步块怎么办?

不,这不安全。

与问题无关:

示例代码的第一个问题:

public void set(int v){
    this.value = v;
}

这是极差的代码质量,真的应该这样写:

public final void setValue(final int value) {
    this.value = value;
}

除了添加 final 修饰符可以改进字节码优化之外,这没有任何性能优势,它只是 setter 的一种设计模式。

示例代码的第二个问题:

public int value(){
    return value;
}

getter 的正确设计模式是:

public final int getValue() {
    return value;
}

示例代码的第三个问题:

private final Object Y = new Object();

字段 'Y' 不是静态的,因此不是常量,该字段的正确命名约定是:

private final Object y = new Object();

示例代码的第四个问题是在没有 space 的括号后放置大括号,我的意思是不做

){

你真的应该这样做:

) {

IMO 你问错了问题。 Java 内存模型不关心对象和 classes。它只讨论变量.

的可见性

synchronized(o) 块的可见性规则非常简单:一个线程在离开 synchronized(o) 块之前对任何变量所做的任何事情都保证在另一个线程之后对任何其他线程可见在同一实例上输入 synchronized 的块,o.

因此,在您的示例中,如果您有一些 X my_x,并且某些线程 A 执行此操作:

synchronized(Y) {
    my_x.set(55);
}

然后当其他线程 B 随后调用 tester.test(my_x) 时,线程 B 将看到线程 A 存储的值。

另一方面,如果线程 A 调用 my_x.set(...) 而没有 Y 上同步,那么 Java 不承诺何时,如果曾经,线程 B 将看到更改。


注意:您的程序通过使锁定对象 Y 成为 Tester class 的 private 成员而公开邀请失败,同时使 test(X) 函数 public。这实际上是在求你(或其他一些程序员)错误地调用 tester.test(some_random_X),其中 some_random_X 是由另一个执行 not lock [=18] 的线程设置的=].