有多个线程访问单个对象。为了避免内存一致性错误,我使用了该对象的同步方法 这是否意味着当我同步该对象时,只有对象的字段是同步的(而不是对象的字段的字段)? 例如:
public class Class1 {
private Object value1;
public Object getValue1() {
return this.value1;
}
public void setValue1(Object value1) {
this.value1 = value1;
}
}
哪个代码是正确的(Class2
或Class3
)以及为什么?
public class Class2 {
private final Class1 object1 = new Class1();
private Object value2;
public synchronized void setValues(Object value1, Object value2) {
object1.setValue1(value1);
this.value2 = value2;
}
public synchronized Object[] getValues() {
return new Object[] { object1.getValue1(), this.value2};
}
}
public class Class3 {
private final Class1 object1 = new Class1();
private Object value2;
public synchronized void setValues(Object value1, Object value2) {
synchronized (object1) {
object1.setValue1(value1);
}
this.value2 = value2;
}
public synchronized Object[] getValues() {
Object value1;
synchronized (object1) {
value1 = object1.getValue1();
}
return new Object[] { value1, this.value2};
}
}
更具体:
Class2 obj = new Class2();
// thread 1
obj.setValues(..., ...);
// thread 2
Object[] values = obj.getValues();
由于setValues
和getValues
都已同步,因此this.value2 = value2;
与return new Object[] {..., this.value2};
之间的Class2
和object1
之间的关系会发生。
但是this.value1 = value1;
呢?无法保证在return this.value1;
Class1
之前发生{{1}}。不是吗?
答案 0 :(得分:0)
他们都是正确的,但仅仅是因为你如何使用它们的具体情况(除了你正在创建的实例的方法之外,没有任何东西可以使用object1
或value2
,因为{ {1}}或object1
和私有实例)。你的主要问题的答案:
这是否意味着当我在该对象上进行同步时,只会同步对象的字段(而不是对象的字段的字段)?
.. 是,只能同步访问该对象的字段,而不是其字段的字段。
这是一个可以证明问题的例子:
value2
有了这个,class Foo {
Class1 c1;
Foo(Class1 c) {
this.c1 = c;
}
synchronized Object getValue1() {
return c1.getValue1();
}
synchronized void setValue1(Object newValue) {
c1.setValue1(newValue);
}
}
的两个实例可能会共享Foo
的相同实例:
Class1
...并且由于同步仅同步对Class1 c1 = new Class1();
Foo f1 = new Foo(c1);
Foo f2 = new Foo(c2);
实例的访问,因此您可以对它们都使用的Foo
实例进行不同步访问。