简体   繁体   English

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

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

There are answers to the question if accessing the state of the object is safe within the synchronized method or block.如果在同步方法或块中访问 object 的 state 是安全的,则有此问题的答案。 My question: Is it safe to access an object X within a synchronized block, where synchronized block is on another object Y and there are multiple writers Threads present for X?我的问题:在同步块中访问 object X 是否安全,其中同步块在另一个 object 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 ?
        }
    }
}      

I know state of the object on which synchronized block is defined is safe to access without a need for volatile, but what if the synchronized block is defined on another object?我知道 object 的 state 的 state 在其上定义了同步块是安全的,无需 volatile,但如果同步块是在另一个 object 上定义的呢?

IMO you are asking the wrong question. IMO 你问错了问题。 The Java Memory Model doesn't concern itself with objects and classes. Java Memory Model 本身不关心对象和类。 It only talks about the visibility of variables .它只谈论变量的可见性。

The visibility rule for synchronized(o) blocks is pretty simple: Whatever one thread does to any variable before it leaves a synchronized(o) block is guaranteed to be visible to any other thread after the other thread subsequently enters a block that is synchronized on the same instance, o . synchronized(o)块的可见性规则非常简单:一个线程在离开synchronized(o)块之前对任何变量所做的任何事情都保证在另一个线程随后进入synchronized的块之后对任何其他线程可见同一个例子, o

So, in your example, if you have some X my_x , and some thread A does this:因此,在您的示例中,如果您有一些X my_x ,并且某个线程 A 这样做:

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

Then when some other thread B subsequently calls tester.test(my_x) , thread B will see the value that was stored by thread A.然后,当其他线程 B 随后调用tester.test(my_x)时,线程 B 将看到线程 A 存储的值。

On the other hand, if thread A calls my_x.set(...) without synchronizing on Y , then Java does not promise when, if ever, the thread B will see the change.另一方面,如果线程 A 调用my_x.set(...)而不同步Y ,则 Java 不会 promise ,如果有的话,线程 B 将看到更改。


Note: Your program openly invites failure by making the lock object, Y , a private member of the Tester class, while making the test(X) function public .注意:您的程序通过将锁 object, Y设置为Tester class 的private成员,同时公开test(X) function ,从而public导致失败。 That practically begs you (or some other programmer) to make the mistake of calling tester.test(some_random_X) where the some_random_X was set by another thread that did not lock Y .这实际上是在请求您(或其他一些程序员)犯错误调用tester.test(some_random_X) ,其中some_random_X是由另一个锁定Y的线程设置的。

No it is not safe.不,这不安全。

Unrelated to the question:与问题无关:

First problem with the example code:示例代码的第一个问题:

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

this is extremely poor code quality and should really be written like this:这是极差的代码质量,真的应该这样写:

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

this has no performance benefit other than addition of the final modifiers may improve bytecode optimization it is just a design pattern for setters.除了添加 final 修饰符可以改善字节码优化之外,这没有任何性能优势,它只是 setter 的一种设计模式。

Second problem with the example code:示例代码的第二个问题:

public int value(){
    return value;
}

the correct design pattern for a getter is: getter 的正确设计模式是:

public final int getValue() {
    return value;
}

Third problem with the example code:示例代码的第三个问题:

private final Object Y = new Object();

the field 'Y' is not static and therefore is not a constant, the correct naming convention for this field would be:字段“Y”不是 static,因此不是常量,该字段的正确命名约定为:

private final Object y = new Object();

The forth problem with the example code is the putting braces after parentheses without a space, what i mean by that is instead of doing示例代码的第四个问题是括号后面没有空格,我的意思是而不是做

){

you should really be doing:你真的应该这样做:

) {

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM