在对象上同步,然后在该对象的字段上同步

时间:2015-04-03 08:06:22

标签: java multithreading synchronization synchronized

有多个线程访问单个对象。为了避免内存一致性错误,我使用了该对象的同步方法 这是否意味着当我同步该对象时,只有对象的字段是同步的(而不是对象的字段的字段)? 例如:

public class Class1 {

    private Object value1;

    public Object getValue1() {
        return this.value1;
    }

    public void setValue1(Object value1) {
        this.value1 = value1;
    }

}

哪个代码是正确的(Class2Class3)以及为什么?

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();

由于setValuesgetValues都已同步,因此this.value2 = value2;return new Object[] {..., this.value2};之间的Class2object1之间的关系会发生。 但是this.value1 = value1;呢?无法保证在return this.value1; Class1之前发生{{1}}。不是吗?

1 个答案:

答案 0 :(得分:0)

他们都是正确的,但仅仅是因为你如何使用它们的具体情况(除了你正在创建的实例的方法之外,没有任何东西可以使用object1value2,因为{ {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实例进行不同步访问。