访问对象Y上定义的同步块中的对象X安全吗



在同步方法或块中访问对象的状态是否安全的问题有答案。我的问题是:访问同步块中的对象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的情况下访问定义了同步块的对象的状态是安全的,但若在另一个对象上定义了同步的块呢?

IMO您问错了问题。Java内存模型本身并不关心对象和类。它只讨论变量的可见性。

synchronized(o)块的可见性规则非常简单:无论一个线程在离开synchronized(o)块之前对任何变量做了什么,都保证在另一个线程随后进入同一实例o上的synchronized块之后,对任何其他线程都是可见的。

因此,在您的示例中,如果您有一些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类的private成员,同时使test(X)函数public,公开地招致失败。这实际上要求您(或其他程序员(犯调用tester.test(some_random_X)的错误,其中some_random_X是由另一个而不是锁定Y的线程设置的。

不,它不安全。

与问题无关:

示例代码的第一个问题:

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

这是非常糟糕的代码质量,应该这样写:

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

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

示例代码的第二个问题:

public int value(){
return value;
}

吸气剂的正确设计模式是:

public final int getValue() {
return value;
}

示例代码的第三个问题:

private final Object Y = new Object();

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

private final Object y = new Object();

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

){

你真的应该做:

) {

相关内容

  • 没有找到相关文章